I want to use CGAL to substitute the vtkCutter when rendering 2D slices of 3D polygonal meshes. To obtain high performance, I use AABB_tree and indeed, the intersections are produced much faster. However, when triangles (or their edges) are coplanar with the query plane, the results are rather arbitrary - likely due to numerical round-off issues. As I need high performance, I use the Simple_cartesian<double> kernel.
Is there a way to control this behaviour in CGAL? For example, can I specify some kind of tolerance so that if two points of a triangle are within this tolerance from a plane - the edge is considered to lie in the plane?
Cheers,
Rostislav.
The code:
#include <iostream>
#include <list>
#include <CGAL/Simple_cartesian.h>
#include <CGAL/AABB_tree.h>
#include <CGAL/AABB_traits.h>
#include <CGAL/AABB_face_graph_triangle_primitive.h>
#include <CGAL/Polyhedron_3.h>
#include <CGAL/IO/Polyhedron_iostream.h>
typedef CGAL::Simple_cartesian<double> K;
typedef K::FT FT;
typedef K::Point_3 Point;
typedef K::Vector_3 Vector;
typedef K::Plane_3 Plane;
typedef K::Segment_3 Segment;
typedef K::Triangle_3 Triangle;
typedef CGAL::Polyhedron_3<K> Polyhedron;
typedef std::list<Segment>::iterator Iterator;
typedef CGAL::AABB_face_graph_triangle_primitive<Polyhedron, CGAL::Default, CGAL::Tag_false> Primitive;
typedef CGAL::AABB_traits<K, Primitive> Traits;
typedef CGAL::AABB_tree<Traits> Tree;
int main()
{
Polyhedron polyhedron;
std::ifstream inFile("mesh.off");
inFile >> polyhedron;
std::ifstream planeIn("plane.txt");
double a[9];
for (int i = 0; i < 9; ++i) {
planeIn >> a[i];
}
Tree tree(polyhedron.facets_begin(), polyhedron.facets_end(), polyhedron);
tree.accelerate_distance_queries();
Point points[] = { { a[0], a[1], a[2] }, { a[3], a[4], a[5] }, { a[6], a[7], a[8] } };
Plane plane_query(points[0], points[1], points[2]);
std::vector<Tree::Intersection_and_primitive_id<Plane>::Type> segments;
tree.all_intersections(plane_query, std::back_inserter(segments));
return EXIT_SUCCESS;
}
Related
I have a simple example where a graph of polygon is created and saved to an svg file. However, the polygon is partially saved only. So how can I resize the graph?
#include <string>
#include <fstream>
#include <boost/geometry.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
#include <boost/geometry/geometries/polygon.hpp>
#include <boost/geometry/geometries/adapted/c_array.hpp>
// Using the boost namespace
using namespace boost::geometry;
// Register the C array points for boost
BOOST_GEOMETRY_REGISTER_C_ARRAY_CS(cs::cartesian)
template <typename Geometry>
void create_svg(std::string const& file_path, Geometry const& geometry, std::string
const& style) {
using PointType = typename point_type<Geometry>::type;
std::ofstream svg_file(file_path.c_str());
svg_mapper<PointType> mapper(svg_file, 2000, 2000);
mapper.add(geometry);
mapper.map(geometry, style);
}
int main() {
model::polygon<model::d2::point_xy<double>, false> polygon;
double points[][2] = {{0., 0.}, {2., 1.}, {3., 3.}, {-0.5, 0.5}, {0., 0.}};
append(polygon, points);
std::string style{"fill-rule:nonzero;fill-opacity:0.5;fill:yellow;stroke:black;stroke-width:2;"};
create_svg("image.svg", polygon, style);
return 0;
}
The output is like:
It seems that somehow the scale factor/bounding box get miscalculated.
Using
bg::svg_mapper<PointType> mapper(svg_file, 400, 400);
works fine. If all coords get scaled at (larger than) integral grid, all is fine.
I tried to isolate any contibuting factor (integral coordinate type, clockwise orientation polygons, SameScale = true template argument for the svg_mapper) but it all seems unrelated. Ubsan did not flag anything. I would report this at the library. Meanwhile, try smaller SVG dimensions to "hide" the issue:
Live On Coliru
#include <fstream>
#include <iostream>
#include <boost/geometry.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
#include <boost/geometry/geometries/polygon.hpp>
// Using the boost namespace
namespace bg = boost::geometry;
template <typename Geometry>
void create_svg(std::string const& file_path, Geometry const& geometry,
std::string const& style)
{
using PointType = typename bg::point_type<Geometry>::type;
std::ofstream svg_file(file_path);
bg::svg_mapper<PointType/*, true*/> mapper(svg_file, 400, 400);
mapper.add(geometry);
mapper.map(geometry, style);
}
template <typename T> void check(T& geo) {
for (std::string reason; !bg::is_valid(geo, reason); bg::correct(geo)) {
std::cout << "Correcting: " << reason << "\n";
}
}
int main()
{
bg::model::polygon<bg::model::d2::point_xy<double>> polygon{
{{0, 0}, {-.5, .5}, {3, 3}, {2, 1}, {0, 0}}};
check(polygon);
std::string style{"fill-rule:nonzero;fill-opacity:0.5;fill:yellow;stroke:"
"black;stroke-width:2;"};
create_svg("image.svg", polygon, style);
}
Rendering:
BREAKTHROUGH
I just noticed that for me Chrome renders the "weird" SVG as
I thought is was strange that is is rendered differently from your question.
I just thought to check with Inkscape, and lo and behold, it comes out "normal":
The x/y rulers seem to indicate correct scaling. So my best theory is that it's a browser-specific limitation that doesn't render "very large" SVG scales well?
I am new to C++ programming and I would like to plot a sine/cosine/square wave but I cannot find any resources to help me with it.
My goal is to produce any wave, and then perform a fourier transform of that wave and produce the resultant wave.
This code should work for you. Just make sure you run it on an IDE that has graphics.h. In many new IDEs graphics.h doesn't come by default and you have to add it first.
#include <iostream>
#include <conio.h>
#include <graphics.h>
#include <math.h>
using namespace std;
int main(){
initwindow(800,600);
int x,y;
line(0,500,getmaxx(),500); //to draw co-ordinate axes
line(500,0,500,getmaxy());
float pi = 3.14;
for(int i = -360; i < 360 ; i++){
x = (int)500+i;
y = (int)500 - sin(i*pi/100)*25;
putpixel(x,y,WHITE); //to plot points on the graph
}
getch(); //to see the resultant graph
closegraph();
return 0;
}
I am trying to draw a koch curve (line) with basic trigonometric conversions.
I couldn't figure out what is the correct angle for newly generated peak point.
Here is my logic:
Given the start point of the line, angle of the line and the length for every segment, create this scheme.
After creating the schemem, treat every sub-lines starting point as new koch curves and repeat the steps.
I suspect the problem is at point 'pt' angle value.
/* Angle for turning downwards after the peak point */
float angle = 2*PI - PI/6;
void koch(Point2D start, float alpha, int d, int noi) {
Point2D p1 = new Point2D(start.x + d*cos(alpha), start.y + d*sin(alpha));
Point2D pt = new Point2D(start.x + d*sqrt(3)*cos(alpha+PI/6), start.y + d*sqrt(3)*sin(alpha+PI/6));
Point2D p2 = new Point2D(start.x + 2*d*cos(alpha), start.y + 2*d*sin(alpha));
Point2D p3 = new Point2D(start.x + 3*d*cos(alpha), start.y + 3*d*sin(alpha));
line(start.x, start.y, p1.x, p1.y);
line(p1.x, p1.y, pt.x, pt.y);
line(pt.x, pt.y, p2.x, p2.y);
line(p2.x, p2.y, p3.x, p3.y);
if(noi != 0) {
koch(start, alpha, d/3, noi-1);
koch(p1, alpha + PI/3, d/3, noi-1);
koch(pt, angle, d/3, noi-1); //Problem is here i suspect
koch(p2, alpha, d/3, noi-1);
}
return;
}
Calling this function with alpha being PI/6 and noi is 2 i get:
I want to get something like:
I was reluctant to answer as I do not code in Unity but as your question after few days still did not have any valid answer here is mine:
I do not see what I would expect in turtle graphics code. See:
Smooth Hilbert curves
and look for turtle_draw in the code. This is what I would expect:
initial string
turtle fractals are represented by a string holding turtle commands. Usual commands are:
f go forward by predetermined step
l turn left (CCW) by predetermined angle in your case 60 deg
r turn right (CW) by predetermined angle in your case 60 deg
For Koch snowflake you should start with triangle so "frrfrrf" the Koch curve starts with single line "f" instead.
iteration/recursion
for each level of iteration/recursion of the fractal you should replace each straight line command f by the triangular bump feature "flfrrflf" (make sure that last direction matches original f command). As the triangle tripled in size you should divide size of the f movement by 3 to stay at the same scale ...
render the string
simply process all the characters of the resulting string and render the lines. There are two approaches how to handle the rotations. Either remember direction angle and inc/dec it by rotation angle and compute the lines as polar coordinates increments (see the code below), or have direction in form of a 2D (or higher dimension) vector and apply rotation formula on it (see the link above).
Here small C++/VCL example of the Koch snowflake:
//---------------------------------------------------------------------------
#include <vcl.h>
#include <math.h>
#pragma hdrstop
#include "win_main.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
Graphics::TBitmap *bmp=new Graphics::TBitmap;
int xs,xs2,ys,ys2,n=0;
AnsiString str;
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
void turtle(TCanvas *scr,float x,float y,float a,float dl,AnsiString s)
{
int i;
char c;
float da=60.0*M_PI/180.0;
scr->MoveTo(x,y);
for (i=1;i<=s.Length();i++)
{
c=s[i];
if (c=='f')
{
x+=dl*cos(a);
y+=dl*sin(a);
scr->LineTo(x,y);
}
if (c=='l') a-=da;
if (c=='r') a+=da;
}
}
//---------------------------------------------------------------------------
AnsiString replace(AnsiString s0,char find,AnsiString replace)
{
int i;
char c;
AnsiString s="";
for (i=1;i<=s0.Length();i++)
{
c=s0[i];
if (c==find) s+=replace;
else s+=c;
}
return s;
}
//---------------------------------------------------------------------------
void draw()
{
str="frrfrrf"; // initial string
for (int i=0;i<n;i++) str=replace(str,'f',"flfrrflf"); // n times replacement
bmp->Canvas->Brush->Color=0x00000000; // just clear screen ...
bmp->Canvas->FillRect(TRect(0,0,xs,ys));
bmp->Canvas->Pen ->Color=0x00FFFFFF; // and some info text
bmp->Canvas->Font ->Color=0x00FFFFFF;
bmp->Canvas->TextOutA(5,5,AnsiString().sprintf("n:%i",n));
float nn=pow(3,n),a;
a=xs; if (a>ys) a=ys; a=0.75*a/nn;
turtle(bmp->Canvas,xs2-(0.5*nn*a),ys2-(0.33*nn*a),0.0,a,str); // render fractal
Form1->Canvas->Draw(0,0,bmp); // swap buffers to avoid flickering
}
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormDestroy(TObject *Sender)
{
delete bmp;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormResize(TObject *Sender)
{
bmp->Width=ClientWidth;
bmp->Height=ClientHeight;
xs=ClientWidth;
ys=ClientHeight;
xs2=xs>>1;
ys2=ys>>1;
draw();
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
void __fastcall TForm1::FormPaint(TObject *Sender)
{
draw();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormMouseWheel(TObject *Sender, TShiftState Shift, int WheelDelta, TPoint &MousePos, bool &Handled)
{
if (WheelDelta<0) if (n<8) n++;
if (WheelDelta>0) if (n>0) n--;
Handled=true;
draw();
}
//---------------------------------------------------------------------------
Ignore the VCL stuff. The important thing here are:
void turtle(TCanvas *scr,float x,float y,float a,float dl,AnsiString s)
which renders the string s on canvas scr (using VCL encapsulated GDI) where x,y is start position a is starting direction angle [rad] and dl is size of line.
AnsiString replace(AnsiString s0,char find,AnsiString replace)
which replace any find characters in s0 by replace pattern returned as a new string.
void draw()
which computes and render the fractal
Here few screenshots:
Now when I look at your code (just a quick look as I am too lazy to analyze your code in depth) you are generating points directly and without the incremental steps needed. Instead you are sort of hard-coding the triangular bump feature which will not work properly for next level of fractal recursion without clever indexing techniques. In your case it stop working properly even in the same level of recursion (on the next line because its oriented differently and you are not rotating but hard-coding the feature instead).
As far as I know basic Koch curve starts with a line, divides the length of step into three and puts a equilateral triangle in the middle:
There are different variations out there if you are interested in, but for basic Koch curve you can start with either two of p1, p2, p3, pt and start points that you drawn and calculate the rest respectively. In each iteration, you can go one level deeper.
Are there any examples of matrix transformations on polygons (cartesian), using Boost Geometry? I am defining the matrix with simple std::vectors.
Also, I could only find 1 example of matrix_transformers using ublas but it's way too convoluted for a simple matrix transformation. If this is the only way though, I'll stick with it, but it would be great to have other options, ad do this with std::vector instead of ublas::matrix.
Here's my solution for anyone who might be interested. Boost geometry actually added a strategy called matrix_transformer that relies on Boost's qvm::mat for matrix transformations. There's not that many examples out there, so here's my code:
#include <boost/geometry.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
#include <boost/geometry/geometries/polygon.hpp>
using namespace boost::geometry::strategy::transform;
typedef boost::geometry::model::d2::point_xy<double> point_2f;
typedef boost::geometry::model::polygon<point_2f> polygon_2f;
int main() {
polygon_2f pol;
boost::geometry::read_wkt("POLYGON((10 10,10 27,24 22,22 10,10 10))", pol);
polygon_2f polTrans;
// Set the rotation angle (in radians)
double angleDeg = 45;
double angleRad = angleDeg * 3.14159 / 180.0;
vector<vector<double> > mat = {{cos(angleRad), sin(angleRad), 0}, {-sin(angleRad), cos(angleRad), 0}, {0, 0, 1}};
// Create the matrix_trasformer for a simple rotation matrix
matrix_transformer<double, 2, 2> rotation(mat[0][0], mat[0][1], mat[0][2], mat[1][0], mat[1][1], mat[1][2], mat[2][0], mat[2][1], mat[2][2]);
// Apply the matrix_transformer
boost::geometry::transform(pol, polTrans, rotation);
// Create svg file to show results
std::ofstream svg("transformationExample.svg");
boost::geometry::svg_mapper<point_2f> mapper(svg, 400, 400);
mapper.add(pol);
mapper.map(pol, "fill-opacity:0.5;fill:rgb(153,204,0);stroke:rgb(153,204,0);stroke-width:2");
mapper.add(polTrans);
mapper.map(polTrans, "fill-opacity:0.5;fill:rgb(153,204,255);stroke:rgb(153,204,255);stroke-width:2");
return 0;
}
And here's my result, where the green polygon is the original and the blue polygon is transformed (remember that the rotation was about the origin):
Can I use the Eigen library to get the rotation matrix which rotates vector A to vector B?
I have been searching for a while, but cannot find related api.
You first have to construct a quaternion and then convert it to a matrix, for instance:
#include <Eigen/Geometry>
using namespace Eigen;
int main() {
Vector3f A, B;
Matrix3f R;
R = Quaternionf().setFromTwoVectors(A,B);
}