get vertices index to save Triangulation - c++

I want to save a triangulation_2D to the next format :
v x1 y1
v x2 y2
...
f v11 v12 v13
f v21 v22 v23
...
where v11 v12 ... are indexes of the points already saved, here what I'm using : (CDT is a Triangulation_2 and _Point is a point_2)
std::vector<_Point> meshpoints;
int find_index(_Point p)
{
bool trouv = false;
unsigned i = 0;
while(i < meshpoints.size() && !trouv)
{
if(p.x() == meshpoints.at(i).x() && p.y() == meshpoints.at(i).y()) trouv = true;
else i++;
}
if(trouv) return i;
return -1;
}
void save_triangulation(CDT triangulation, std::string link = "unkown.txt")
{
std::cout << "Saving IVGE . . ." ;
std::ofstream triangulation_file(link);
for(CDT::Vertex_iterator vertex = triangulation.vertices_begin() ; vertex != triangulation.vertices_end() ; vertex++)
meshpoints.push_back(vertex->point());
for(unsigned i = 0 ; i < meshpoints.size() ; i++)
triangulation_file << "v " << std::setprecision(15) << meshpoints.at(i) << std::endl;
for(CDT::Face_iterator c = triangulation.faces_begin(); c != triangulation.faces_end(); c++)
{
triangulation_file << "f " << find_indice(c->vertex(0)->point()) << " " << find_indice(c->vertex(1)->point()) << " " << find_indice(c->vertex(2)->point()) <<std::endl;
}
std::cout << " Done\n" ;
}
my question is : is there any method to optimize find_index, cause I have a triangulation of more then 2M points.
I changed the format of out put file, here is the new format:
v x1 y1
v x2 y2
...
f v11 v12 v13 a11 a12 a13
f v21 v22 v23 a21 a22 a23
...
where a12 ... are triangle neighbors. the function becomes :
std::ofstream Ivge_file(link);
unsigned Vertx_index = 0;
Ivge_file << std::setprecision(15);
for(CDT::Vertex_iterator vertex = IVGE.vertices_begin() ; vertex != IVGE.vertices_end() ; vertex++)
{
Triangulation::Vertex_handle vertx_h = vertex;
vertx_h->info() = Vertx_index;
Vertx_index++;
Ivge_file << "v " << vertex->point() << std::endl;
}
int id=0;
for(CDT::Face_iterator c = IVGE.faces_begin(); c != IVGE.faces_end(); c++,id++)
c->info()._Id = id;
for(CDT::Face_iterator c = IVGE.faces_begin(); c != IVGE.faces_end(); c++)
Ivge_file << "f " << c->vertex(0)->info() << " " << c->vertex(1)->info() << " " << c->vertex(2)->info() << " " << c->neighbor(0)->info()._Id << " " << c->neighbor(1)->info()._Id << " " << c->neighbor(2)->info()._Id << std::endl;

I changed the format of out put file, here is the new format:
v x1 y1
v x2 y2
...
f v11 v12 v13 a11 a12 a13
f v21 v22 v23 a21 a22 a23
...
where a12 ... are triangle neighbors. the function becomes :
std::ofstream Ivge_file(link);
unsigned Vertx_index = 0;
Ivge_file << std::setprecision(15);
for(CDT::Vertex_iterator vertex = IVGE.vertices_begin() ; vertex != IVGE.vertices_end() ; vertex++)
{
Triangulation::Vertex_handle vertx_h = vertex;
vertx_h->info() = Vertx_index;
Vertx_index++;
Ivge_file << "v " << vertex->point() << std::endl;
}
int id=0;
for(CDT::Face_iterator c = IVGE.faces_begin(); c != IVGE.faces_end(); c++,id++)
c->info()._Id = id;
for(CDT::Face_iterator c = IVGE.faces_begin(); c != IVGE.faces_end(); c++)
Ivge_file << "f " << c->vertex(0)->info() << " " << c->vertex(1)->info() << " " << c->vertex(2)->info() << " " << c->neighbor(0)->info()._Id << " " << c->neighbor(1)->info()._Id << " " << c->neighbor(2)->info()._Id << std::endl;

Related

Remove vector lines which are too close to each other?

I'm currently using boost::polygon::detail::resize() function to enlarge or shrink the outline of a polygon by a specific size. This is working well and gives proper results.
Now in some cases, depending on the input shape, the resulting polygon (red) contains vector lines which are very close to each other (black line):
What I want to do is to have a minimum distance over all neighbouring lines of such a polygon. For this example this means, the resulting polygon needs to be modified and a vector line (blue) has to be added, replacing the red lines below of it. This of course would change the shape of the polygon but would keep it conform to the minimum-distance-rule.
In this example picture given above, the new, blue line would have the length of the required minimum distance.
My questions: are there any boost-functions available which could do that job? If yes: which ones and how have they to be used?
Thanks!
Converted your image into code using:
That's:
Point
A(-25.74, 2.5),
B( 14.96, 12.96),
C( 31.07, -2.16),
D( 37, -27.74),
E( 29.37, -51.63),
F( 46.62, -25.48),
G( 48.17, 3.63),
H( 41.53, 20.31),
I( 77.57, 32.04);
String ls{A, B, C, D, E, F, G, H, I};
Using
using Point = bgm::d2::point_xy<double>;
using String = bgm::linestring<Point>;
Let's reproduce the angle measurements:
Live On Coliru
#include <boost/geometry.hpp>
#include <boost/geometry/views/segment_view.hpp>
#include <boost/geometry/geometries/point_xyz.hpp>
#include <iostream>
#include <fstream>
namespace bg = boost::geometry;
namespace bgm = bg::model;
using Point = bgm::d2::point_xy<double>;
using String = bgm::linestring<Point>;
using bg::wkt;
static inline auto angle_rad(Point a, Point b) {
bg::subtract_point(a, b);
return atan2(a.y(), a.x());
}
int main()
{
// clang-format off
Point
A(-25.74, 2.5),
B( 14.96, 12.96),
C( 31.07, -2.16),
D( 37, -27.74),
E( 29.37, -51.63),
F( 46.62, -25.48),
G( 48.17, 3.63),
H( 41.53, 20.31),
I( 77.57, 32.04);
// clang-format on
String ls{A, B, C, D, E, F, G, H, I};
if (std::string reason; !bg::is_valid(ls, reason)) {
std::cout << reason << "\n";
bg::correct(ls);
}
std::cout << wkt(ls) << "\n";
auto desc_p = [&ls](Point const& p) {
static auto names = "ABCDEFGHIJ";
assert(not std::less<>{}(&ls.back(), &p));
assert(not std::less<>{}(&p, &ls.front()));
return std::string(names + (&p - &ls.front()), 1);
};
auto desc = [=](auto it) {
return desc_p(*it->first) + desc_p(*it->second);
};
assert(ls.size() > 1);
auto a = bg::segments_begin(ls), b = std::next(a), e = bg::segments_end(ls);
for (; b != e; ++a, ++b) {
// segment pair *a and *b
auto pointing_angle = [](auto it) {
return angle_rad(*it->first, *it->second);
};
auto aa = pointing_angle(a);
auto ab = pointing_angle(b);
auto deg = [](auto rad) { return rad / M_PI * 180; };
std::cout << "angle " << deg(fmod(ab - aa + 3 * M_PI, 2 * M_PI))
<< " between " //
<< desc(a) << " " << deg(aa) << " vs " //
<< desc(b) << " " << deg(ab) << "\n";
}
{
// Declare a stream and an SVG mapper
std::ofstream svg("output.svg");
bg::svg_mapper<Point> mapper(svg, 400, 400);
// Add geometries such that all these geometries fit on the map
mapper.add(ls);
mapper.map(ls, "fill-opacity:0.3;fill:rgb(51,0,0);stroke:rgb(51,0,0);stroke-width:1");
for (auto& p : ls)
mapper.text(p, desc_p(p), "");
}
}
Prints
LINESTRING(-25.74 2.5,14.96 12.96,31.07 -2.16,37 -27.74,29.37 -51.63,46.62 -25.48,48.17 3.63,41.53 20.31,77.57 32.04)
angle 122.402 between AB -165.587 vs BC 136.816
angle 146.236 between BC 136.816 vs CD 103.052
angle 149.236 between CD 103.052 vs DE 72.2875
angle 344.301 between DE 72.2875 vs EF -123.411
angle 210.363 between EF -123.411 vs FG -93.0479
angle 204.754 between FG -93.0479 vs GH -68.2934
angle 86.322 between GH -68.2934 vs HI -161.971
With the side-effect of writing output.svg containing
Performing a cut-off
Detecting a sharp angle, we can check the cutoff length that would be required for the distance between the legs to grow beyond min_distance:
auto seg_angle = [](auto it) {
return angle_rad(*it->first, *it->second);
};
auto rel = fmod(seg_angle(b) - seg_angle(a) + 3 * M_PI, 2 * M_PI);
auto inner = fabs(2 * M_PI - rel);
bool is_sharp = inner < M_PI / 2;
if (is_sharp) {
std::cout << " ---- sharp angle, min_distance: " << min_distance
<< " (" << color << ")\n";
auto deg = [](auto rad) { return rad / M_PI * 180; };
std::cout << "angle " << deg(inner) << " between " << desc(a) << " and " << desc(b) << "\n";
auto length_a = bg::length(*a);
auto length_b = bg::length(*b);
std::cout << "len(" << desc(a) << "): " << length_a << "\n";
std::cout << "len(" << desc(b) << "): " << length_b << "\n";
std::cout << "distance(" << desc(P1) << " - " << desc(P3) << "): " << bg::distance(P1, P3) << "\n";
auto cutoff = min_distance / tan(inner);
std::cout << "cutoff: " << cutoff << "\n";
Let's create a helper to manually interpolate the cutoff points:
static inline String do_cutoff(String s, long double amount)
{
assert(s.size() >= 2);
auto delta = s[1];
bg::subtract_point(delta, s[0]);
auto l = bg::length(s);
if (l > 0) {
bg::multiply_value(delta, std::min(amount, l) / l);
bg::add_point(s[0], delta);
}
return s;
}
Now we can use it to get new mid-points instead of P2:
String fs = do_cutoff({P2, P1}, cutoff);
String ss = do_cutoff({P2, P3}, cutoff);
std::reverse(fs.begin(), fs.end());
// assert that end points didn't change
assert(bg::equals(fs.front(), P1));
assert(bg::equals(ss.back(), P3));
Now there's the degenerate case where both legs are too short for the cutoff, meaning the mid-point will disappear:
if (bg::length(*a) < cutoff && bg::length(*b) < cutoff) {
// both legs vanish, connect P1 to P3 directly
auto it = ls.begin() + index_of_p2;
std::cout << "Dropping " << desc(*it) << " (" << desc(P2) << " "
<< wkt(P2) << ")\n";
ls.erase(it);
// note that distance (P1, P3) might still exceed min_distance
// behaviour here is not specified in question
break; // invalidated the loop iterators!
}
Next up, there might be one leg that disappears:
if (bg::length(*a) < cutoff) { // P1 P2 P3 becomes P1 P3' P3
update(P2, ss.front());
} else if (bg::length(*b) < cutoff) { // P1 P2 P3 becomes P1 P1' P3
update(P2, fs.back());
} else {
So far so good. If none of the legs disappear, we need to cut-off the sharp point by introducing an extra point (and updating the original mid-point):
update(P2, ss.front());
// adding a point (invalidating the segment iterators)
std::cout << "Adding " << wkt(fs.back()) << " as X "
<< " before " << desc(P2) << "\n";
names.insert(names.begin() + index_of_p2, "X");
auto added = ls.insert(ls.begin() + index_of_p2, fs.back());
assert(bg::equals(*added, fs.back()));
break; // invalidated the loop iterators!
}
Live Demo
Live On Coliru
#include <boost/geometry.hpp>
#include <boost/geometry/geometries/point_xyz.hpp>
#include <boost/geometry/views/segment_view.hpp>
#include <fstream>
#include <iostream>
namespace bg = boost::geometry;
namespace bgm = bg::model;
using Point = bgm::d2::point_xy<double>;
using String = bgm::linestring<Point>;
using bg::wkt;
static inline auto angle_rad(Point a, Point b) {
bg::subtract_point(a, b);
return atan2(a.y(), a.x());
}
static inline String do_cutoff(String s, long double amount)
{
assert(s.size() >= 2);
auto delta = s[1];
bg::subtract_point(delta, s[0]);
auto l = bg::length(s);
if (l > 0) {
bg::multiply_value(delta, std::min(amount, l) / l);
bg::add_point(s[0], delta);
}
return s;
}
struct Test {
String ls;
std::vector<std::string> names;
double const min_distance;
std::string color, dash_pattern, other_style;
std::string desc(Point const& p) const
{
return names.at(&p - &ls.front());
};
std::string desc(bg::segment_iterator<String const> it) const
{
return desc(*it->first) + desc(*it->second);
};
void perform_cutoff();
};
void Test::perform_cutoff()
{
if (min_distance == 0)
return; // keep original
assert(ls.size() > 1);
auto a = bg::segments_begin(ls), b = std::next(a), e = bg::segments_end(ls);
for (; b != e; ++a, ++b) {
// segments a,b form a joint, let's call it P1 P2 P3
auto& P1 = *a->first;
auto& P2 = *a->second;
auto& P3 = *b->second;
// keep in mind a->second and b->first alias the same point here
assert(a->second == b->first);
auto seg_angle = [](auto it) {
return angle_rad(*it->first, *it->second);
};
auto rel = fmod(seg_angle(b) - seg_angle(a) + 3 * M_PI, 2 * M_PI);
auto inner = fabs(2 * M_PI - rel);
bool is_sharp = inner < M_PI / 2;
if (is_sharp) {
std::cout << " ---- sharp angle, min_distance: " << min_distance
<< " (" << color << ")\n";
auto deg = [](auto rad) { return rad / M_PI * 180; };
std::cout << "angle " << deg(inner) << " between " << desc(a) << " and " << desc(b) << "\n";
auto length_a = bg::length(*a);
auto length_b = bg::length(*b);
std::cout << "len(" << desc(a) << "): " << length_a << "\n";
std::cout << "len(" << desc(b) << "): " << length_b << "\n";
std::cout << "distance(" << desc(P1) << " - " << desc(P3) << "): " << bg::distance(P1, P3) << "\n";
auto cutoff = min_distance / tan(inner);
std::cout << "cutoff: " << cutoff << "\n";
String fs = do_cutoff({P2, P1}, cutoff);
String ss = do_cutoff({P2, P3}, cutoff);
std::reverse(fs.begin(), fs.end());
// assert that end points didn't change
assert(bg::equals(fs.front(), P1));
assert(bg::equals(ss.back(), P3));
std::cout << wkt(ls) << "\n";
auto update = [this](Point const& p, Point const& value) {
std::cout << "Updating " << desc(p) << " from " << wkt(p)
<< " to " << wkt(value) << "\n";
bg::assign(const_cast<Point&>(p), value);
names[&p - &ls.front()] += "'";
};
// For modifying we need the index to the middle point:
auto const index_of_p2 = &P2 - &ls.front();
if (bg::length(*a) < cutoff && bg::length(*b) < cutoff) {
// both legs vanish, connect P1 to P3 directly
auto it = ls.begin() + index_of_p2;
std::cout << "Dropping " << desc(*it) << " (" << desc(P2) << " "
<< wkt(P2) << ")\n";
ls.erase(it);
// note that distance (P1, P3) might still exceed min_distance
// behaviour here is not specified in question
break; // invalidated the loop iterators!
}
if (bg::length(*a) < cutoff) { // P1 P2 P3 becomes P1 P3' P3
update(P2, ss.front());
} else if (bg::length(*b) < cutoff) { // P1 P2 P3 becomes P1 P1' P3
update(P2, fs.back());
} else {
update(P2, ss.front());
// adding a point (invalidating the segment iterators)
std::cout << "Adding " << wkt(fs.back()) << " as X "
<< " before " << desc(P2) << "\n";
names.insert(names.begin() + index_of_p2, "X");
auto added = ls.insert(ls.begin() + index_of_p2, fs.back());
assert(bg::equals(*added, fs.back()));
break; // invalidated the loop iterators!
}
}
}
}
int main()
{
// clang-format off
Point
A(-25.74, 2.5),
B( 14.96, 12.96),
C( 31.07, -2.16),
D( 37, -27.74),
E( 29.37, -51.63),
F( 46.62, -25.48),
G( 48.17, 3.63),
H( 41.53, 20.31),
I( 77.57, 32.04);
// clang-format on
{
String const original_ls{A, B, C, D, E, F, G, H, I};
if (std::string reason; !bg::is_valid(original_ls, reason)) {
std::cout << reason << "\n";
return 1;
}
}
Test testcases[]{
{
{A, B, C, D, E, F, G, H, I},
{"A", "B", "C", "D", "E", "F", "G", "H", "I", "J"},
0, // keep original
"grey", "1 1",
},
{
{A, B, C, D, E, F, G, H, I},
{"A", "B", "C", "D", "E", "F", "G", "H", "I", "J"},
5,
"green", "2 1",
},
{
{A, B, C, D, E, F, G, H, I},
{"A", "B", "C", "D", "E", "F", "G", "H", "I", "J"},
8,
"red", "1 2",
},
{
{A, B, C, D, E, F, G, H, I},
{"A", "B", "C", "D", "E", "F", "G", "H", "I", "J"},
12,
"blue", "2 3",
},
};
std::ofstream svg("output.svg");
bg::svg_mapper<Point> mapper(svg, 400, 400);
for (auto& c : testcases) {
c.perform_cutoff();
std::cout << wkt(c.ls) << "\n";
mapper.add(c.ls);
mapper.map(
c.ls,
"stroke:" + c.color + ";stroke-width:1;stroke-dasharray:" + c.dash_pattern);
for (auto& p : c.ls)
mapper.text(p, c.desc(p), "fill:" + c.color + ";font-size:x-small");
}
}
Prints
LINESTRING(-25.74 2.5,14.96 12.96,31.07 -2.16,37 -27.74,29.37 -51.63,46.62 -25.48,48.17 3.63,41.53 20.31,77.57 32.04)
---- sharp angle, min_distance: 5 (green)
angle 15.6986 between DE and EF
len(DE): 25.0789
len(EF): 31.3271
distance(D - F): 9.8819
cutoff: 17.7897
LINESTRING(-25.74 2.5,14.96 12.96,31.07 -2.16,37 -27.74,29.37 -51.63,46.62 -25.48,48.17 3.63,41.53 20.31,77.57 32.04)
Updating E from POINT(29.37 -51.63) to POINT(39.1658 -36.7802)
Adding POINT(34.7824 -34.6836) as X before E'
LINESTRING(-25.74 2.5,14.96 12.96,31.07 -2.16,37 -27.74,34.7824 -34.6836,39.1658 -36.7802,46.62 -25.48,48.17 3.63,41.53 20.31,77.57 32.04)
---- sharp angle, min_distance: 8 (red)
angle 15.6986 between DE and EF
len(DE): 25.0789
len(EF): 31.3271
distance(D - F): 9.8819
cutoff: 28.4636
LINESTRING(-25.74 2.5,14.96 12.96,31.07 -2.16,37 -27.74,29.37 -51.63,46.62 -25.48,48.17 3.63,41.53 20.31,77.57 32.04)
Updating E from POINT(29.37 -51.63) to POINT(45.0432 -27.8703)
LINESTRING(-25.74 2.5,14.96 12.96,31.07 -2.16,37 -27.74,45.0432 -27.8703,46.62 -25.48,48.17 3.63,41.53 20.31,77.57 32.04)
---- sharp angle, min_distance: 12 (blue)
angle 15.6986 between DE and EF
len(DE): 25.0789
len(EF): 31.3271
distance(D - F): 9.8819
cutoff: 42.6953
LINESTRING(-25.74 2.5,14.96 12.96,31.07 -2.16,37 -27.74,29.37 -51.63,46.62 -25.48,48.17 3.63,41.53 20.31,77.57 32.04)
Dropping E (E POINT(29.37 -51.63))
LINESTRING(-25.74 2.5,14.96 12.96,31.07 -2.16,37 -27.74,46.62 -25.48,48.17 3.63,41.53 20.31,77.57 32.04)
And the resulting output.svg:
Conclusion
Hopefully that helps.
Note that the code has limitations as written, because for simplicity I used
segment_iterator.
Due to the segment-iterator loop, currently only the first sharp corner
might be treated, unless they can be treated without invalidating the
iterators. You'd either have to repeat the loop or rewrite the loop in
terms of indices instead of using the segment_iterators.
Also due to the segment iterators, I resorted to an ugly const_cast to
update existing points, instead of going throught the geometry interface.
This would not pass my own code review :)
Finally, nothing is decided when even the distance P1-P3 directly exceeded the
min_distance (you didn't specify anything about this potentiality in the
question).

Heap corrupted and strange breakpoint in Runge Kutta diff eq solver

I'm trying to implement Runga Kutta method for solving the Lorenz differential equation system.
At some point, the program always stops at a breakpoint which I can't see, and then throws an error about heap corruption.
Something must be wrong with the way I use the pointers, but I have no idea what's not working well.
Here's my code:// Runge_Kutta.cpp : This file contains the 'main' function. Program execution begins and ends there.
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <stdlib.h>
#include <iostream>
#include <stdio.h>
#include <fstream>
#include <vector>
#include <time.h>
#include <math.h>
#include <fstream>
#include <chrono>
using namespace std;
const int dimension=3;
double* F = new double(3);
double p1 = 10;
double p2 = 28;
double p3 = 8.0 / 3.0;
double* K1 = new double(3);
double* K2 = new double(3);
double* K3 = new double(3);
double* K4 = new double(3);
double* X = new double(3);
double* t = new double(3);
double a = 0;
double b = 100;
const int N = 1000;
//double * x=new double[N];
double dt = (b - a) / N;
void f(double *F,double *x, double *t)
{
double dx1 = p1 * (x[1] - x[0]);
double dx2 = x[0] * (p2 - x[2]) - x[1];
double dx3 = x[0] * x[1] - p3 * x[2];
//cout << "dx-ek: " << dx1 << " " << dx2 << " " << dx3 << "\n";
F[0] = dx1;
F[1] = dx2;
F[2] = dx3;
}
double* RK4(double* x, double *t, double dt)
{
f(K1, x, t);
//cout << "K1: " << K1[0] << " " << K1[1] << " " << K1[2] << "\n";
for (int i = 0; i < dimension; i++)
{
X[i] = x[i] + dt * K1[i] * 0.5;
}
f(K2, X, t);
//cout << "K2: " << K2[0] << " " << K2[1] << " " << K2[2] << "\n";
for (int i = 0; i < dimension; i++)
{
X[i] = x[i] + dt * K2[i] * 0.5;
}
f(K3, X, t);
//cout << "K3: " << K3[0] << " " << K3[1] << " " << K3[2] << "\n";
for (int i = 0; i < dimension; i++)
{
X[i] = x[i] + dt * K2[i] * 0.5;
}
f(K4, X, t);
//cout << "K4: " << K4[0] << " " << K4[1] << " " << K4[2] << "\n";
for (int i = 0; i < dimension; i++)
{
//cout << "Ennek nem kéne 0-nak lennie: " << K1[i] * 0.1666666 + K2[i] * 0.33333333 + K3[i] * 0.3333333 + K4[i] * 0.1666666 << '\n';
x[i] = x[i] + dt * (K1[i] * 0.1666666 + K2[i] * 0.33333333 + K3[i] * 0.3333333 + K4[i] * 0.1666666);
//cout << "Return előtt előtt: " << x[0] << " " << x[1] << " " << x[2] << "\n";
}
//cout << "Return előtt: " << x[0] << " " << x[1] << " " << x[2] << "\n";
return x;
}
int main()
{
cout << "Let's start!";
std::ofstream myfile;
myfile.open("solution.csv");
double* x = new double(3);
/*
for(int z=0;z<dimension;z++)
{
//cout << "WHat the heck?";
x[z]= 0;
}
*/
x[0] = -5.0;
x[1] = 0.0;
x[2] = 0.0;
auto start=std::chrono::high_resolution_clock::now();
for (int j = 0; j < N; j++)
{
RK4(x, t, dt);
//cout << j << "\n";
//cout << "Return után "<< x[0] << " " <<x[1]<<" "<<x[2]<<" it: "<<j << "\n";
//cout << "\n";
for (int u = 0; u < dimension; u++)
{
myfile << x[u];
if (u <= dimension - 2) myfile << ",";
else myfile << "\n";
}
}
auto elapsed = std::chrono::high_resolution_clock::now()-start;
long long microseconds = std::chrono::duration_cast<std::chrono::microseconds>(elapsed).count();
cout << "Simulation time: " << microseconds << " microsec" << endl << endl;
myfile.close();```

Wrong multiplication of quaternions

I made my quaternion realization and to test it I used boost. I test it in cycle and I always have errors in multiplication and division. Then I used Wolfram to find out who was wrong and I find out that boost was wrong.
I am not sure that the boost library was Wong, maybe some one can find out what is going on?
Console output example:
0
Operation : [ * ]
First vector = [ -41.4168 -92.2373 -33.0126 -42.2364 ]
Second vector = [ -67.8087 -60.3523 58.8705 36.3265 ]
My multiplication = [ 719.45 10041.3 5700.03 -6062.97 ]
Boost multiplication = [ 719.45 10041.3 10041.3 5700.03 ]
main.cpp
#include "quaternion.h"
#include <boost/math/quaternion.hpp>
#include <random>
#include <time.h>
#include <QDebug>
using boost::math::quaternion;
double fRand(double fMin, double fMax)
{
double f = (double)rand() / RAND_MAX;
return fMin + f * (fMax - fMin);
}
bool isEqual(double a, double b){
return std::abs(a-b) < std::numeric_limits<double>::epsilon();
}
bool isEqual(Quaternion& quat1, quaternion<double> quat2){
if (!isEqual(quat2.R_component_1(), quat1.real)) return false;
if (!isEqual(quat2.R_component_2(), quat1.imagine.data.at(0))) return false;
if (!isEqual(quat2.R_component_3(), quat1.imagine.data.at(1))) return false;
if (!isEqual(quat2.R_component_4(), quat1.imagine.data.at(2))) return false;
return true;
}
int main () {
std::srand(std::time(nullptr));
Quaternion compR;
quaternion<double> boost;
double a1, a2, a3, a4,
b1, b2, b3, b4;
try {
for (unsigned int i=0; i<10000000; ++i){
a1 = fRand(-100, 100);
a2 = fRand(-100, 100);
a3 = fRand(-100, 100);
a4 = fRand(-100, 100);
b1 = fRand(-100, 100);
b2 = fRand(-100, 100);
b3 = fRand(-100, 100);
b4 = fRand(-100, 100);
Quaternion comp1{a1,a2,a3,a4};
Quaternion comp2{b1,b2,b3,b4};
quaternion<double> a(a1,a2,a3,a4);
quaternion<double> b(b1,b2,b3,b4);
//if (i%50000==0)
qDebug() << i;
compR = comp1+comp2;
boost = a+b;
if (!isEqual(compR, boost))
throw std::runtime_error("+");
compR = comp1-comp2;
boost = a-b;
if (!isEqual(compR, boost))
throw std::runtime_error("-");
compR = comp1*comp2;
boost = a*b;
if (!isEqual(compR, boost))
throw std::runtime_error("*");
compR = comp1/comp2;
boost = a/b;
if (!isEqual(compR, boost))
throw std::runtime_error("/");
}
} catch (const std::runtime_error& error) {
qDebug() << "Operation : [" << error.what() << "]";
qDebug() << " First vector = [" << a1 << " " << a2 << " " << " " << a3 << " " << a4 << "]\n" <<
"Second vector = [" << b1 << " " << b2 << " " << " " << b3 << " " << b4 << "]";
qDebug() << " My multiplication = [" << compR.real << " " << compR.imagine.data.at(0) << " " << compR.imagine.data.at(1)<< " " << compR.imagine.data.at(2) << "]\n" <<
"Boost multiplication = [" << boost.R_component_1() << " " << boost.R_component_2() << " " << boost.R_component_2() << " " << boost.R_component_3() << "]";
}
return 0;
}
Full project:https://github.com/Yegres5/quaternion
You have two issues:
you have a bug printing the boost quaternion (you print the index 2 twice)
use a larger epsilon. Using epsilon as it is can only be suitable, if your numbers around 1. Your result is around 10,000, so you need to use at least 10,000x larger epsilon. At this still may not be large enough, as quaternion multiplication uses several operations, each one can add some additional error. So, to be safe, multiply epsilon further by ~10 or so.

What is wrong with my function for Lagrange?

GsVec curve_eval::eval_lagrange(float t, float numberofsegmentsn, const GsArray<GsVec>& ctrlpnts) //f(t) = sum of p.i * B.i(t)
{
//float interval = 1 / numberofsegmentsn; //so if 4, then 0.25
float interval = 1 / ctrlpnts.size();
//remember that for interval that is put in above, it's based on numbers of ctrlpnts
//for lagrange, let t
GsVec ft(0.0f, 0.0f, 0.0f);
int sizeofctrlpnts = ctrlpnts.size();
float result = 0;
std::cout << "interval = " << interval << " \\ number of segments = " << numberofsegmentsn << " \\ ctrlpnts.size() = " << ctrlpnts.size() << "\n";
float tt = 0;
float ti[50] = { 0 };
float tj[50] = { 0 }; //only this might be used
for (int x = 0; x < ctrlpnts.size(); x++) //changed from 'numberofsegmentsn'
{
tj[x] = tt;//
std::cout << "tt in tj[" << x << "]= " << tt << "\n";
tt = tt + interval;
}
float tb = 1;
tt = 1;
int i = 0;
for (int i = 0; i < ctrlpnts.size(); i ++)
{
tt = 1;
tb = 1;
for (int j = 0; j < ctrlpnts.size(); j++) //
{
if (i != j)
{
std::cout << "Before cal: i = " << i << " :: j = " << j << " :: tt = " << tt << " :: tb = " << tb << " :: t = " << t << " :: tj[i" << j << "] = " << tj[j] << " :: tj[j" << i << "] = " << tj[i] << "\n";
tt = (t - tj[j]) * tt;
tb = (tj[i] - tj[j])* tb;
std::cout << "After cal: tt = " << tt << " :: tb = " << tb << "\n";
}
//t gotta change
}
result = tt / tb;
ft = ft+(ctrlpnts[i]*result);
}
return ft;
Above is my written algorithm for Lagrange function for opengl.
Following link is the screenshot of the formula that i had to impliment, http://imgur.com/gkuaxVm.
I have been tweaking it for awhile, and i can't seem to find what is wrong with it.

sin() cos() ring formula

This is the source code:
#include <Windows.h>
#include <string>
#include <iostream>
#include <fstream>
#include <math.h>
using namespace std;
#define d_open fstream::in | fstream::out | fstream::app | fstream::ate
#define Space " "
#define d_qq "\""
struct point3D
{
float X;
float Y;
float Z;
};
struct ObjectStruct
{
point3D T_LT;
point3D T_LB;
point3D T_RT;
point3D T_RB;
point3D B_LT;
point3D B_LB;
point3D B_RT;
point3D B_RB;
};
void CreateObject(ObjectStruct myobject)
{
fstream outmap;
outmap.open("prefab.map", d_open);
float * X = new float[6];
float * Y = new float[6];
float * Z = new float[6];
float * X2 = new float[6];
float * Y2 = new float[6];
float * Z2 = new float[6];
float * X3 = new float[6];
float * Y3 = new float[6];
float * Z3 = new float[6];
X[0] = myobject.T_LT.X;
Y[0] = myobject.T_LT.Y;
Z[0] = myobject.T_LT.Z;
X2[0] = myobject.T_RT.X;
Y2[0] = myobject.T_RT.Y;
Z2[0] = myobject.T_RT.Z;
X3[0] = myobject.T_RB.X;
Y3[0] = myobject.T_RB.Y;
Z3[0] = myobject.T_RB.Z;
X[1] = myobject.B_LB.X;
Y[1] = myobject.B_LB.Y;
Z[1] = myobject.B_LB.Z;
X2[1] = myobject.B_RB.X;
Y2[1] = myobject.B_RB.Y;
Z2[1] = myobject.B_RB.Z;
X3[1] = myobject.B_RT.X;
Y3[1] = myobject.B_RT.Y;
Z3[1] = myobject.B_RT.Z;
X[2] = myobject.T_LT.X;
Y[2] = myobject.T_LT.Y;
Z[2] = myobject.T_LT.Z;
X2[2] = myobject.T_LB.X;
Y2[2] = myobject.T_LB.Y;
Z2[2] = myobject.T_LB.Z;
X3[2] = myobject.B_LB.X;
Y3[2] = myobject.B_LB.Y;
Z3[2] = myobject.B_LB.Z;
X[3] = myobject.B_RT.X;
Y[3] = myobject.B_RT.Y;
Z[3] = myobject.B_RT.Z;
X2[3] = myobject.B_RB.X;
Y2[3] = myobject.B_RB.Y;
Z2[3] = myobject.B_RB.Z;
X3[3] = myobject.T_RB.X;
Y3[3] = myobject.T_RB.Y;
Z3[3] = myobject.T_RB.Z;
X[4] = myobject.T_RT.X;
Y[4] = myobject.T_RT.Y;
Z[4] = myobject.T_RT.Z;
X2[4] = myobject.T_LT.X;
Y2[4] = myobject.T_LT.Y;
Z2[4] = myobject.T_LT.Z;
X3[4] = myobject.B_LT.X;
Y3[4] = myobject.B_LT.Y;
Z3[4] = myobject.B_LT.Z;
X[5] = myobject.B_RB.X;
Y[5] = myobject.B_RB.Y;
Z[5] = myobject.B_RB.Z;
X2[5] = myobject.B_LB.X;
Y2[5] = myobject.B_LB.Y;
Z2[5] = myobject.B_LB.Z;
X3[5] = myobject.T_LB.X;
Y3[5] = myobject.T_LB.Y;
Z3[5] = myobject.T_LB.Z;
outmap
<< "{" << endl
<< "( " << X[0] << Space << Y[0] << Space << Z[0] << " ) "
<< "( " << X2[0] << Space << Y2[0] << Space << Z2[0] << " ) "
<< "( " << X3[0] << Space << Y3[0] << Space << Z3[0] << " ) "
<< "YELLOW"
<< " [ 1 0 0 0 ] [ 0 -1 0 0 ] 0 1 1 " << endl
<< "( " << X[1] << Space << Y[1] << Space << Z[1] << " ) "
<< "( " << X2[1] << Space << Y2[1] << Space << Z2[1] << " ) "
<< "( " << X3[1] << Space << Y3[1] << Space << Z3[1] << " ) "
<< "YELLOW"
<< " [ 1 0 0 0 ] [ 0 -1 0 0 ] 0 1 1 " << endl
<< "( " << X[2] << Space << Y[2] << Space << Z[2] << " ) "
<< "( " << X2[2] << Space << Y2[2] << Space << Z2[2] << " ) "
<< "( " << X3[2] << Space << Y3[2] << Space << Z3[2] << " ) "
<< "YELLOW"
<< " [ 0 1 0 0 ] [ 0 0 -1 0 ] 0 1 1 " << endl
<< "( " << X[3] << Space << Y[3] << Space << Z[3] << " ) "
<< "( " << X2[3] << Space << Y2[3] << Space << Z2[3] << " ) "
<< "( " << X3[3] << Space << Y3[3] << Space << Z3[3] << " ) "
<< "YELLOW"
<< " [ 0 1 0 0 ] [ 0 0 -1 0 ] 0 1 1 " << endl
<< "( " << X[4] << Space << Y[4] << Space << Z[4] << " ) "
<< "( " << X2[4] << Space << Y2[4] << Space << Z2[4] << " ) "
<< "( " << X3[4] << Space << Y3[4] << Space << Z3[4] << " ) "
<< "YELLOW"
<< " [ 1 0 0 0 ] [ 0 0 -1 0 ] 0 1 1 " << endl
<< "( " << X[5] << Space << Y[5] << Space << Z[5] << " ) "
<< "( " << X2[5] << Space << Y2[5] << Space << Z2[5] << " ) "
<< "( " << X3[5] << Space << Y3[5] << Space << Z3[5] << " ) "
<< "YELLOW"
<< " [ 1 0 0 0 ] [ 0 0 -1 0 ] 0 1 1 " << endl
<< "}" << endl;
delete [] X;
delete [] Y;
delete [] Z;
delete [] X2;
delete [] Y2;
delete [] Z2;
delete [] X3;
delete [] Y3;
delete [] Z3;
outmap.flush();
//
outmap.close();
}
int main(int argc, char ** argv)
{
//HANDLE console = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTitle("Prefab Creator by Raichu (xgm.ru,d3scene.ru)");
Sleep(200);
SetConsoleTitle("PrefabTool by Raichu v0.1");
int select = 0;
cout << "Available shapes: 1-Ring, 2-Cube, 3-Triangle" << endl;
cin >> select;
if (select == 1)
{
cout << "Enter quantity of objects:" << endl;
int quality;
cin >> quality;
if (quality > 200 || quality < 10)
{
cout << "Error... Restart..." << endl;
return main(argc, argv);
}
cout << "Enter Ring radius:(example 20.0)" << endl;
float WhSz;
cin >> WhSz;
float inangle = 360 / quality;
//system("cls");
float X1_, X2_, Y1_, Y2_;
float X1, X2, Y1, Y2;
float a = 0;
X1_ = WhSz * cos(a);
Y1_ = WhSz * sin(a);
X2_ = (WhSz + 4) * cos(a);
Y2_ = (WhSz + 4) * sin(a);
a = inangle;
for (; a <= 360; )
{
X1 = WhSz * cos(a);
Y1 = WhSz * sin(a);
X2 = (WhSz + 4) * cos(a);
Y2 = (WhSz + 4) * sin(a);
#pragma region TEST
//cout << "X:" << X1 << " Y:" << Y1 << endl;
/* COORD xy;
xy.X = X1;
xy.Y = Y1;
SetConsoleCursorPosition(console, xy);
cout << "+" << endl;
xy.X = X2;
xy.Y = Y2;
SetConsoleCursorPosition(console, xy);
cout << "?" << endl;*/
#pragma endregion
ObjectStruct NewObject;
/* down */
NewObject.B_LB.Z = NewObject.B_LT.Z = NewObject.B_RB.Z = NewObject.B_RT.Z = -5;
/* top */
NewObject.T_LB.Z = NewObject.T_LT.Z = NewObject.T_RB.Z = NewObject.T_RT.Z = 5;
NewObject.T_LT.X = NewObject.B_LT.X = X2_;
NewObject.T_LT.Y = NewObject.B_LT.Y = Y2_;
NewObject.T_LB.X = NewObject.B_LB.X = X1_;
NewObject.T_LB.Y = NewObject.B_LB.Y = Y1_;
NewObject.T_RT.X = NewObject.B_RT.X = X2;
NewObject.T_RT.Y = NewObject.B_RT.Y = Y2;
NewObject.T_RB.X = NewObject.B_RB.X = X1;
NewObject.T_RB.Y = NewObject.B_RB.Y = Y1;
CreateObject(NewObject);
X1_ = X1;
Y1_ = Y1;
X2_ = X2;
Y2_ = Y2;
//a += inangle/3; // - Create SUN
a += inangle;
}
}
system("pause");
return 0;
}
problem code:
if (select == 1)
{
cout << "Enter quantity of objects:" << endl;
int quality;
cin >> quality;
if (quality > 200 || quality < 10)
{
cout << "Error... Restart..." << endl;
return main(argc, argv);
}
cout << "Enter Ring radius:(example 20.0)" << endl;
float WhSz;
cin >> WhSz;
float inangle = 360 / quality;
//system("cls");
float X1_, X2_, Y1_, Y2_;
float X1, X2, Y1, Y2;
float a = 0;
X1_ = WhSz * cos(a);
Y1_ = WhSz * sin(a);
X2_ = (WhSz + 4) * cos(a);
Y2_ = (WhSz + 4) * sin(a);
a = inangle;
for (; a <= 360; )
{
X1 = WhSz * cos(a);
Y1 = WhSz * sin(a);
X2 = (WhSz + 4) * cos(a);
Y2 = (WhSz + 4) * sin(a);
#pragma region TEST
//cout << "X:" << X1 << " Y:" << Y1 << endl;
/* COORD xy;
xy.X = X1;
xy.Y = Y1;
SetConsoleCursorPosition(console, xy);
cout << "+" << endl;
xy.X = X2;
xy.Y = Y2;
SetConsoleCursorPosition(console, xy);
cout << "?" << endl;*/
#pragma endregion
ObjectStruct NewObject;
/* down */
NewObject.B_LB.Z = NewObject.B_LT.Z = NewObject.B_RB.Z = NewObject.B_RT.Z = -5;
/* top */
NewObject.T_LB.Z = NewObject.T_LT.Z = NewObject.T_RB.Z = NewObject.T_RT.Z = 5;
NewObject.T_LT.X = NewObject.B_LT.X = X2_;
NewObject.T_LT.Y = NewObject.B_LT.Y = Y2_;
NewObject.T_LB.X = NewObject.B_LB.X = X1_;
NewObject.T_LB.Y = NewObject.B_LB.Y = Y1_;
NewObject.T_RT.X = NewObject.B_RT.X = X2;
NewObject.T_RT.Y = NewObject.B_RT.Y = Y2;
NewObject.T_RB.X = NewObject.B_RB.X = X1;
NewObject.T_RB.Y = NewObject.B_RB.Y = Y1;
CreateObject(NewObject);
X1_ = X1;
Y1_ = Y1;
X2_ = X2;
Y2_ = Y2;
//a += inangle/3; // - Create SUN
a += inangle;
}
}
I want to create a ring using objects. It turns 3 turns (3 layers) instead of one. How to fix it? It seems the problem in degrees, but I can not understand.
(sorry for that that I use a translator Google Translate)
sin and cos take radians as input, not degrees. You'll need to convert your angles to radians before passing them into sin and cos:
X1 = WhSz * cos(a * 3.141592654 / 180.0);