Postgis + boost::geometry + C++ - postgresql

I have the following wtk:
POLYGON((0 0, 10 0, 10 11, 11 10, 0 10))
In boost::geometry we can get this polygon representation using
boost::geometry::dsv(polygon," "," "," ");
How I can apply postgis st_makevalid function to a boost::geometry polygon?
I suppose it something like:
#include "libpq/libpq-fs.h"
#include "../libpq-fe.h"
.
.
.
std::string geom = "POLYGON" + boost::geometry::dsv(multipoly," "," "," ");
res = PQexecParams(conn, "SELECT st_makevalid(geom) FROM ....
I do not want to connect to a data base, I just want to repair a polygon or multipolygon with the postgis function st_makevalid.

I doubt you need PostGIS for this operation.
I also doubt there is a way to "make it valid". Because the polygon has a clear self intersection:
Here's how you do the validation and correction in Boost Geometry itself:
Live On Coliru
#include <boost/geometry.hpp>
#include <boost/geometry/geometries/geometries.hpp>
#include <boost/geometry/io/io.hpp>
#include <boost/geometry/algorithms/equals.hpp>
#include <iostream>
namespace bg = boost::geometry;
namespace bgm = boost::geometry::model;
template<typename G>
bool check(G const& g) {
std::string reason;
bool valid = bg::is_valid(g, reason);
if (valid) std::cout << "Valid (dsv): " << bg::dsv(g) << "\n";
else std::cout << "Invalid: " << reason << "\n";
return valid;
}
int main() {
using pt = bgm::d2::point_xy<double>;
using poly = bgm::polygon<pt>;
poly p;
bg::read_wkt("POLYGON((0 0, 10 0, 10 11, 11 10, 0 10))", p);
while (!check(p)) {
auto same = p;
bg::correct(p);
if (bg::equals(p, same)) {
std::cout << "Out of ideas\n";
break;
}
}
}
And note the output:
Invalid: Geometry is defined as closed but is open
Invalid: Geometry has invalid self-intersections. A self-intersection point was found at (10, 10); method: i; operations: u/i; segment IDs {source, multi, ring, segment}: {0, -1, -1, 1}/{0, -1, -1, 3}
Out of ideas
If your source actually contains self-intersections like that, it's hard to tell what you'd like. Perhaps you want to look at
Split Self intersecting Polygon into non self intersecting polygon
Area of self-intersecting polygon

Related

My vscode is part English part Chinese, how to change it to complete English?

As mentioned in the title, I have part of my vscode Chinese, which is troublesome since looking up error codes in English will be easier. How can I turn it into complete English? I've tried How to set Visual Studio Code Terminal output to English and it didn't work for me.
Since someone asked for the code to be post in text, this is the code (I'm using a tutorial code for camera calibration from opencv, so the error code appearing also confused me):
#include <iostream>
#include <opencv2/calib3d.hpp>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
int main(int argc, char **argv) {
(void)argc;
(void)argv;
std::vector<cv::String> fileNames;
cv::glob("../calibration/Image*.png", fileNames, false);
cv::Size patternSize(25 - 1, 18 - 1);
std::vector<std::vector<cv::Point2f>> q(fileNames.size());
std::vector<std::vector<cv::Point3f>> Q;
// 1. Generate checkerboard (world) coordinates Q. The board has 25 x 18
// fields with a size of 15x15mm
int checkerBoard[2] = {25,18};
// Defining the world coordinates for 3D points
std::vector<cv::Point3f> objp;
for(int i = 1; i<checkerBoard[1]; i++){
for(int j = 1; j<checkerBoard[0]; j++){
objp.push_back(cv::Point3f(j,i,0));
}
}
std::vector<cv::Point2f> imgPoint;
// Detect feature points
std::size_t i = 0;
for (auto const &f : fileNames) {
std::cout << std::string(f) << std::endl;
// 2. Read in the image an call cv::findChessboardCorners()
cv::Mat img = cv::imread(fileNames[i]);
cv::Mat gray;
cv::cvtColor(img, gray, cv::COLOR_RGB2GRAY);
bool patternFound = cv::findChessboardCorners(gray, patternSize, q[i], cv::CALIB_CB_ADAPTIVE_THRESH + cv::CALIB_CB_NORMALIZE_IMAGE + cv::CALIB_CB_FAST_CHECK);
// 2. Use cv::cornerSubPix() to refine the found corner detections
if(patternFound){
cv::cornerSubPix(gray, q[i],cv::Size(11,11), cv::Size(-1,-1), cv::TermCriteria(cv::TermCriteria::EPS + cv::TermCriteria::MAX_ITER, 30, 0.1));
Q.push_back(objp);
}
// Display
cv::drawChessboardCorners(img, patternSize, q[i], patternFound);
cv::imshow("chessboard detection", img);
cv::waitKey(0);
i++;
}
cv::Matx33f K(cv::Matx33f::eye()); // intrinsic camera matrix
cv::Vec<float, 5> k(0, 0, 0, 0, 0); // distortion coefficients
std::vector<cv::Mat> rvecs, tvecs;
std::vector<double> stdIntrinsics, stdExtrinsics, perViewErrors;
int flags = cv::CALIB_FIX_ASPECT_RATIO + cv::CALIB_FIX_K3 +
cv::CALIB_ZERO_TANGENT_DIST + cv::CALIB_FIX_PRINCIPAL_POINT;
cv::Size frameSize(1440, 1080);
std::cout << "Calibrating..." << std::endl;
// 4. Call "float error = cv::calibrateCamera()" with the input coordinates
// and output parameters as declared above...
float error = cv::calibrateCamera(Q, q, frameSize, K, k, rvecs, tvecs, flags);
std::cout << "Reprojection error = " << error << "\nK =\n"
<< K << "\nk=\n"
<< k << std::endl;
// Precompute lens correction interpolation
cv::Mat mapX, mapY;
cv::initUndistortRectifyMap(K, k, cv::Matx33f::eye(), K, frameSize, CV_32FC1,
mapX, mapY);
// Show lens corrected images
for (auto const &f : fileNames) {
std::cout << std::string(f) << std::endl;
cv::Mat img = cv::imread(f, cv::IMREAD_COLOR);
cv::Mat imgUndistorted;
// 5. Remap the image using the precomputed interpolation maps.
cv::remap(img, imgUndistorted, mapX, mapY, cv::INTER_LINEAR);
// Display
cv::imshow("undistorted image", imgUndistorted);
cv::waitKey(0);
}
return 0;
}

Visualize PCD containing custom double point structure

I have created a custom double point-type for storing the point position in the PCD file. I required the double data type since my points are in global coordinates and have very large values (of order 10^6 to 10^7) and require good precision. Since the values are large and the default FLOAT32 precision is limited, there is considerable data approximation which is also visible during visualization.
I created this PCD by transforming the raw pointcloud with the initial global reference coordinate from GPS in the data bag that I have. I am using a 15 point precision.
I created a separate script for visualizing this custom point-type PCD. But by visually comparing, I cannot see any considerable difference between the FLOAT32 and double data-type PCD's.
Raw_float_pcd_visualization
Transformed_float_pcd_visualization
Transformed_double_pcd_visualization
You can see that the transformed_double and transformed_float PCD's are quite similar and approximated. While the raw_float PCD is quite good as compared to these two.
I am attaching the PCD files for reference:
raw_float
transformed_float
transformed_double
I think that I am skipping some things while loading the pointcloud and there are some more changes that need to be done in order to visualize the points with double point precision.
I used "pcl_viewer" from pcl_tools for visualizing FLOAT type PCD's.
Code for visualizaing custom DOUBLE point-structure PCD:
#define PCL_NO_PRECOMPILE
#include <iostream>
// #include "double_viz/pcl_double.h"
#include <pcl-1.7/pcl/common/common.h>
#include <pcl-1.7/pcl/io/pcd_io.h>
#include <pcl-1.7/pcl/visualization/pcl_visualizer.h>
#include <pcl-1.7/pcl/console/parse.h>
#include <pcl-1.7/pcl/point_cloud.h>
#include <pcl-1.7/pcl/point_types.h>
namespace pcl
{
#define PCL_ADD_UNION_POINT4D_DOUBLE \
union EIGEN_ALIGN16 { \
double data[4]; \
struct { \
double x; \
double y; \
double z; \
}; \
};
struct _PointXYZDouble
{
PCL_ADD_UNION_POINT4D_DOUBLE; // This adds the members x,y,z which can also be accessed using the point (which is float[4])
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
};
struct EIGEN_ALIGN16 PointXYZDouble : public _PointXYZDouble
{
inline PointXYZDouble (const _PointXYZDouble &p)
{
x = p.x; y = p.y; z = p.z; data[3] = 1.0;
}
inline PointXYZDouble ()
{
x = y = z = 0.0;
data[3] = 1.0;
}
inline PointXYZDouble (double _x, double _y, double _z)
{
x = _x; y = _y; z = _z;
data[3] = 1.0;
}
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
};
}
POINT_CLOUD_REGISTER_POINT_STRUCT (pcl::_PointXYZDouble,
(double, x, x)
(double, y, y)
(double, z, z)
)
POINT_CLOUD_REGISTER_POINT_WRAPPER(pcl::PointXYZDouble, pcl::_PointXYZDouble)
// This function displays the help
void
showHelp(char * program_name)
{
std::cout << std::endl;
std::cout << "Usage: " << program_name << " cloud_filename.[pcd]" << std::endl;
std::cout << "-h: Show this help." << std::endl;
}
// This is the main function
int
main (int argc, char** argv)
{
// Show help
if (pcl::console::find_switch (argc, argv, "-h") || pcl::console::find_switch (argc, argv, "--help"))
{
showHelp (argv[0]);
return 0;
}
// Fetch point cloud filename in arguments | Works with PCD
std::vector<int> filenames;
if (filenames.size () != 1)
{
filenames = pcl::console::parse_file_extension_argument (argc, argv, ".pcd");
if (filenames.size () != 1)
{
showHelp (argv[0]);
return -1;
}
}
// Load file | Works with PCD and PLY files
pcl::PointCloud<pcl::PointXYZDouble>::Ptr source_cloud (new pcl::PointCloud<pcl::PointXYZDouble> ());
if (pcl::io::loadPCDFile (argv[filenames[0]], *source_cloud) < 0)
{
std::cout << "Error loading point cloud " << argv[filenames[0]] << std::endl << std::endl;
showHelp (argv[0]);
return -1;
}
// Visualization
// printf( "\nPoint cloud colors : white = original point cloud\n"
// " red = transformed point cloud\n");
pcl::visualization::PCLVisualizer viewer ("Visualize double PCL");
// Define R,G,B colors for the point cloud
pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZDouble> source_cloud_color_handler (source_cloud, 100, 100, 100);
// We add the point cloud to the viewer and pass the color handler
viewer.addPointCloud (source_cloud, source_cloud_color_handler, "original_cloud");
viewer.addCoordinateSystem (1.0, "cloud", 0);
viewer.setBackgroundColor(0.05, 0.05, 0.05, 0); // Setting background to a dark grey
viewer.setPointCloudRenderingProperties (pcl::visualization::PCL_VISUALIZER_OPACITY, 1, "original_cloud");
viewer.setPointCloudRenderingProperties (pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 1, "original_cloud");
viewer.setPointCloudRenderingProperties (pcl::visualization::PCL_VISUALIZER_LINE_WIDTH, 1, "original_cloud");
//viewer.setPosition(800, 400); // Setting visualiser window position
while (!viewer.wasStopped ()) // Display the visualiser until 'q' key is pressed
{
viewer.spinOnce ();
}
return 0;
}
In the raw_float file, the size field has been defined as 4 bytes each: SIZE 4 4 4 4,
to be read as double it should be SIZE 8 8 8 8.
With your current implementation each field is being read as Float32

Saving Nef polyhedron as Polyhedron_3 or Surface_mesh gives different results

I wanted to save a Nef polyhedron into an OFF file for visualizing it. As written in the CGAL Nef polyhedra user manual (see paragraphs 5.4 and 5.5), a Nef polyhedron can be converted both to a Polyhedron_3 or a Surface_mesh.
However, I noticed that when converting to those structures and then saving it into an OFF file, the results are different.
Here I report the code for a minimal example:
#include <list>
#include <iostream>
#include <fstream>
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
#include <CGAL/Polyhedron_3.h>
#include <CGAL/Nef_polyhedron_3.h>
#include <CGAL/IO/Nef_polyhedron_iostream_3.h>
#include <CGAL/Surface_mesh.h>
#include <CGAL/boost/graph/convert_nef_polyhedron_to_polygon_mesh.h>
typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel;
typedef Kernel::Point_3 Point_3;
typedef CGAL::Surface_mesh<Point_3> Mesh;
typedef CGAL::Polyhedron_3<Kernel> Polyhedron_3;
typedef CGAL::Nef_polyhedron_3<Kernel> Nef_polyhedron;
typedef Kernel::Vector_3 Vector_3;
typedef Kernel::Aff_transformation_3 Aff_transformation_3;
int convertStlToOff(const char* inputFilename, const char* outputFilename)
{
//read 80 bytes and put in std::cerr
std::ifstream obj(inputFilename, std::ios::in | std::ios::binary);
for (int i = 0; i < 80; i++) {
boost::uint8_t c;
obj.read(reinterpret_cast<char*>(&c), sizeof(c));
std::cerr << c;
}
std::cerr << std::endl;
//read 4 bytes and initialize number of triangles
boost::uint32_t N32;
obj.read(reinterpret_cast<char*>(&N32), sizeof(N32));
unsigned int N = N32;
std::cerr << N << " triangles" << std::endl;
//reserve space for N faces
std::vector<Point_3> points;
std::map<Point_3, int> pmap;
typedef boost::tuple<int, int, int> Face;
std::vector<Face> faces;
faces.reserve(N);
//read all faces
int number_of_points = 0;
int number_of_snapped_points = 0;
for (int i = 0; i < N; i++)
{
//read face normal (it is ignored)
float normal[3];
obj.read(reinterpret_cast<char*>(&normal[0]), sizeof(normal[0]));
obj.read(reinterpret_cast<char*>(&normal[1]), sizeof(normal[1]));
obj.read(reinterpret_cast<char*>(&normal[2]), sizeof(normal[2]));
//read coordinates of all 3 points
int index[3];
for (int j = 0; j < 3; j++)
{
float x, y, z;
obj.read(reinterpret_cast<char*>(&x), sizeof(x));
obj.read(reinterpret_cast<char*>(&y), sizeof(y));
obj.read(reinterpret_cast<char*>(&z), sizeof(z));
Point_3 p(x, y, z);
if (pmap.find(p) == pmap.end())
{
// check brute force if there is a close point
bool found_close_point = false;
/*for (int k = 0; k < points.size(); k++)
{
if (sqrt(CGAL::squared_distance(p, points[k])) < 0.00001)
{
index[j] = k;
found_close_point = true;
number_of_snapped_points++;
}
}*/
if (!found_close_point)
{
points.push_back(p);
index[j] = number_of_points;
pmap[p] = number_of_points++;
}
}
else {
index[j] = pmap[p];
}
}
faces.push_back(boost::make_tuple(index[0], index[1], index[2]));
//read two additional bytes, and ignore them
char c;
obj.read(reinterpret_cast<char*>(&c), sizeof(c));
obj.read(reinterpret_cast<char*>(&c), sizeof(c));
}
std::cerr << number_of_snapped_points << " snapped points" << std::endl;
std::ofstream outputFile(outputFilename);
outputFile.precision(20);
outputFile << "OFF\n" << points.size() << " " << faces.size() << " 0" << std::endl;
for (int i = 0; i < points.size(); i++)
{
outputFile << points[i] << std::endl;
}
for (int i = 0; i < faces.size(); i++)
{
outputFile << "3 " << boost::get<0>(faces[i]) << " " << boost::get<1>(faces[i]) << " " << boost::get<2>(faces[i]) << std::endl;
}
return 0;
}
void fill_cube_1(Polyhedron_3 & poly)
{
std::string input =
"OFF\n\
8 12 0\n\
-1 -1 -1\n\
-1 1 -1\n\
1 1 -1\n\
1 -1 -1\n\
-1 -1 1\n\
-1 1 1\n\
1 1 1\n\
1 -1 1\n\
3 0 1 3\n\
3 3 1 2\n\
3 0 4 1\n\
3 1 4 5\n\
3 3 2 7\n\
3 7 2 6\n\
3 4 0 3\n\
3 7 4 3\n\
3 6 4 7\n\
3 6 5 4\n\
3 1 5 6\n\
3 2 1 6";
std::stringstream ss;
ss << input;
ss >> poly;
}
enum savingModality
{
SAVE_AS_POLYHEDRON_3 = 0,
SAVE_AS_SURFACE_MESH = 1,
};
int saveNefObjectInOffFile(Nef_polyhedron offObject, const char* filename, savingModality modality)
{
if (!offObject.is_simple())
{
printf("Object is not simple. Cannot convert to mesh or polyhedron\n");
return 1;
}
std::ofstream outStream;
outStream.open(filename);
if (modality == SAVE_AS_POLYHEDRON_3)
{
Polyhedron_3 outputPolyhedron;
offObject.convert_to_Polyhedron(outputPolyhedron);
outStream << outputPolyhedron;
}
else if (modality == SAVE_AS_SURFACE_MESH)
{
Mesh outputMesh;
CGAL::convert_nef_polyhedron_to_polygon_mesh(offObject, outputMesh);
outStream << outputMesh;
}
outStream.close();
return 0;
}
int main()
{
int ret;
//construct nef object #1
Polyhedron_3 cube1;
fill_cube_1(cube1);
Nef_polyhedron nefObject1(cube1);
//construct nef object #2
Nef_polyhedron nefObject2(cube1);
Aff_transformation_3 scale2(1, 0, 0,
0, 1, 0,
0, 0, 1,
2);
nefObject2.transform(scale2);
Aff_transformation_3 translation2(CGAL::TRANSLATION, Vector_3(-0.5, -0.5, -0.5));
nefObject2.transform(translation2);
//construct nef object #3
Nef_polyhedron nefObject3;
nefObject3 = nefObject1 - nefObject2;
//save results into .off file
ret = saveNefObjectInOffFile(nefObject3, "out1.off", SAVE_AS_POLYHEDRON_3);
ret = saveNefObjectInOffFile(nefObject3, "out2.off", SAVE_AS_SURFACE_MESH);
return 0;
}
and the screenshots of the visualization of the two files: saving as Polyhedron_3 and saving as Surface_mesh. As you can see, it seems like if some faces were missing.
My question is: "Why the results are visualized different?"
The output to Polyhedron_3 is triangulated while the output to Surface_mesh is not. There is a bug in meshlab to display non convex faces I guess.
Look at the doc you'll see that there is a Boolean parameter to trigger or not the triangulation.

Merging .root files causing copies of the merged file

I wrote a macro to loop through and merge several .root files of data collected hourly, in an attempt to take several hourly files and turn it into daily files instead. For some reason it is creating several copies of it and all the information within it. For example, when I try to look into the tree containing the data from all the trees, it says "clusters_Tree; 61".
I am attaching my macro, any idea how I could fix this?
#include "TChain.h"
#include "TTree.h"
#include "TParameter.h"
#include "TFile.h"
#include <iostream>
Double_t elow = 0.13;
Double_t ehigh = 100.;
void makeShort(TString year, TString month, TString day){
TChain* c = new TChain("clusters_tree");
TChain* d = new TChain("finfo");
int nFiles = 0;
double efact = 6.04E-3;
TString infolder = "/data/directory1/";
TString contains = year + month + day;
TString outfolder = "/data/directory1/";
TFile* fout = new
TFile(outfolder+"/short_test"+contains+".root","RECREATE");
TSystemDirectory dir(infolder, infolder);
TList *files = dir.GetListOfFiles();
if (files){
TSystemFile *file;
TString fname;
TIter next(files);
while ((file=(TSystemFile*)next())) {
fname = file->GetName();
if (file->IsDirectory() && fname.Contains(contains)) {
nFiles += c->Add(infolder+fname+"/*.root");
d->Add(infolder+fname+"/*.root");
}
}
cout << "Found " << nFiles << " files" << endl;
}
TTree* details = new TTree("details","details");
details->Branch("nFiles",&nFiles);
details->Branch("conversion",&efact);
TTree* t = c->CloneTree(0);
TParameter<double>* q = NULL;
c->SetBranchAddress("charge_total",&q);
Int_t nentries = c->GetEntries();
for(Int_t i=0; i<nentries; i++){
if(i%100000==0)
std::cout << "Processing cluster " << i << " of " << nentries << std::endl;
c->GetEntry(i);
Double_t e = q->GetVal()*efact;
if(e>elow && e<ehigh)
t->Fill();
}
TTree* f = d->CloneTree();
t->Write();
f->Write();
details->Write();
fout->Close();
}
You should really be using hadd. A default ROOT build should already have the binary.
That said, I see you are essentially filling a new tree. The way to do is to create a TChain, and merge to write back (as done by hadd). The clusters_Tree; 61 that you see, are not exactly copies. These are known as cycles, and are more like versions. I'm guessing you have 61 files (maybe 60)? They are probably because you use TTree::CloneTree(0) instead of TChain::Merge(..).

OpenCV equivalent for Matlab's rdivide?

For example we have expression using rdivide in Matlab:
B = bsxfun(#rdivide, A, A(4,:));
How can we write equavalent expression for opencv?
Opencv has divide function, but seems it can't be used for matrix with different dimensions:
Mat t1= Mat::ones(2,3,CV_64FC1);
Mat t2= Mat::ones(1,3,CV_64FC1);
Mat dst;
divide(t1,t2,dst);
this don't work, so we need to replicate one row to matrix to match dimensions of t1 or use divide with 1 row in cycle.
My solution for opencv(A modified inplace):
for(int i=0;i<A.rows;++i)
{
divide(A.row(i),A.row(3),A.row(i));
}
Is there any simpler way?
You can use the repeat function of OpenCV to replicate a matrix.
The equivalent OpenCV code for the above mentioned MATLAB command is following:
cv::Mat B = A/cv::repeat(A.row(3),4,1);
In addition to #sgarizvi solution, you may find this wrapper to Matlab rdivide helpful:
#include <opencv2\opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;
Mat rdivide(const Mat& A, const Mat& B)
{
int nx = A.cols / B.cols;
int ny = A.rows / B.rows;
return A / repeat(B, ny, nx);
}
Mat rdivide(const Mat& A, double d)
{
return A / d;
}
int main()
{
Mat1f A = (Mat1f(3, 5) << 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);
Mat B = rdivide(A, A.row(2)); // Divide by matrix, works also for cols: e.g. A.col(2)
Mat C = rdivide(A, 2); // Divide by scalar
cout << "A: " << endl << A << endl << endl;
cout << "B: " << endl << B << endl << endl;
cout << "C: " << endl << C << endl << endl;
return 0;
}