In my code, I organize objects into a regular Cartesian grid (such as 10x10). Often given a point, I need to test whether the point intersects grid and if so, which bins contain the point. I already have my own implementation but I don't like to hassle with precision issues.
So, does CGAL has a 2D regular Cartesian grid?
You can use CGAL::points_on_square_grid_2 to generate the grid points. CGAL kernels provide Kernel::CompareXY_2 functors, which you can use to figure out the exact location of your query point on the grid. For example you can sort your grid points and then use std::lower_bound followed by CGAL::orientation or CGAL::collinear on the appropriate elements of your range. You could also build an arrangement, but this would be an overkill.
Here is a sample code.
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
#include <CGAL/point_generators_2.h>
#include <CGAL/random_selection.h>
#include <CGAL/Polygon_2_algorithms.h>
using namespace CGAL;
using K= Exact_predicates_exact_constructions_kernel;
using Point =K::Point_2;
using Creator = Creator_uniform_2<double, Point>;
using Grid = std::vector<Point>;
const int gridSide = 3;
void locate_point (Point p, Grid grid);
int main ()
{
Grid points;
points_on_square_grid_2(gridSide * gridSide, gridSide * gridSide, std::back_inserter(points), Creator());
std::sort(points.begin(), points.end(), K::Less_xy_2());
std::cout << "Grid points:\n";
for (auto& p:points)
std::cout << p << '\n';
std::cout << "\ncorner points:\n";
Grid cornerPoints{points[0], points[gridSide - 1], points[gridSide * gridSide - 1],
points[gridSide * (gridSide - 1)]};
for (auto& p:cornerPoints)
std::cout << p << '\n';
std::cout << '\n';
Point p1{-8, -8};
Point p2{-10, 3};
Point p3{-9, -8};
Point p4{0, 4};
Point p5{1, 5};
locate_point(p1, points);
locate_point(p2, points);
locate_point(p3, points);
locate_point(p4, points);
locate_point(p5, points);
}
void locate_point (Point p, Grid grid)
{
if (grid.empty())
{
std::cout << "Point " << p << " not in grid";
return;
}
// check if point is in grid
Grid cornerPoints{grid[0], grid[gridSide - 1], grid[gridSide * gridSide - 1], grid[gridSide * (gridSide - 1)]};
auto point_is = CGAL::bounded_side_2(cornerPoints.begin(), cornerPoints.end(), p);
switch (point_is)
{
case CGAL::ON_UNBOUNDED_SIDE:
std::cout << "Point " << p << " not in grid\n";
return;
case CGAL::ON_BOUNDARY:
std::cout << "Point " << p << " on grid boundary\n";
return;
case CGAL::ON_BOUNDED_SIDE:
std::cout << "Point " << p << " is in grid\n";
}
auto f = std::lower_bound(grid.begin(), grid.end(), p, K::Less_xy_2());
auto g = std::find_if(f, grid.end(), [&p] (const Point& gridpoint)
{ return K::Less_y_2()(p, gridpoint); });
if (CGAL::collinear(p, *g, *(g - 1)))
{
std::cout << "Point " << p << " on grid side between points " << *(g - 1) << " and " << *g << '\n';
return;
}
std::cout << "Point " << p << " in bin whose upper right point is " << *g << '\n';
return;
}
Output:
Grid points:
-9 -9
-9 0
-9 9
0 -9
0 0
0 9
9 -9
9 0
9 9
corner points:
-9 -9
-9 9
9 9
9 -9
Point -8 -8 is in grid
Point -8 -8 in bin whose upper right point is 0 0
Point -10 3 not in grid
Point -9 -8 on grid boundary
Point 0 4 is in grid
Point 0 4 on grid side between points 0 0 and 0 9
Point 1 5 is in grid
Point 1 5 in bin whose upper right point is 9 9
Related
I want to calculate the apparent area of a polygon from a view point. Say, you are looking at a 2 x 2 meters square from across, the apparent area for you would be 4 m2.
Now image the square is rotated somehow, then the apparent area would be smaller. To do this, I figured I could use the following logic:
V3_c (center of mass of the polygon)
V3_v (viewer's position)
Construct a plane that goes through V3_v with the normal of (V3_c - V3_v).normalize()
Project the polygon onto this plane and calculate the area
How can I do this in CGAL?
UPDATE:
Upon #mgimeno's suggestions I've used the following (almost pseudo) code.
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/centroid.h>
#include <iostream>
#include <vector>
#include "print_utils.h"
typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
typedef CGAL::Polygon_with_holes_2<Kernel> Polygon_with_holes_2;
typedef Kernel::Point_2 Point_2;
typedef Kernel::Point_3 Point_3;
typedef Kernel::Plane_3 Plane_3;
typedef Kernel::Vector_3 Vector_3;
typedef Kernel::FT ValueType;
using namespace std;
int main(int argc, char* argv[])
{
Point_3 viewer(0, 0, 0);
cout << "Viewer: " << viewer << endl;
Point_3 a(-5, -5, 5);
Point_3 b(-5, -5, -5);
Point_3 c(5, -5, -5);
Point_3 d(5, -5, 5);
cout << "Surface: " << a << ", " << b << ", " << c << ", " << d << endl;
std::vector<Point_3> vertices;
vertices.push_back(a);
vertices.push_back(b);
vertices.push_back(c);
vertices.push_back(d);
Point_3 center = CGAL::centroid(vertices.begin(), vertices.end(), CGAL::Dimension_tag<0>());
cout << "Center of surface: " << center << endl;
Vector_3 normal = center - viewer;
Plane_3 plane(viewer, normal);
cout << "Plane passing thorough viewer orthogonal to surface: " << plane << endl;
Point_3 pa = plane.projection(a);
Point_3 pb = plane.projection(b);
Point_3 pc = plane.projection(c);
Point_3 pd = plane.projection(d);
cout << "Projected surface onto the plane: " << pa << ", " << pb << ", " << pc << ", " << pd << endl;
Point_2 pa2 = plane.to_2d(pa);
Point_2 pb2 = plane.to_2d(pb);
Point_2 pc2 = plane.to_2d(pc);
Point_2 pd2 = plane.to_2d(pd);
cout << "to_2d of the projected plane: " << pa2 << ", " << pb2 << ", " << pc2 << ", " << pd2 << endl;
std::vector<Point_2> vertices2;
vertices2.push_back(pa2);
vertices2.push_back(pb2);
vertices2.push_back(pc2);
vertices2.push_back(pd2);
ValueType result;
CGAL::area_2(vertices2.begin(), vertices2.end(), result);
cout << "Area of to_2d'ed vertices: " << result << endl;
return EXIT_SUCCESS;
}
The output is:
Viewer: 0 0 0
Surface: -5 -5 5, -5 -5 -5, 5 -5 -5, 5 -5 5
Center of surface: 0 -5 0
Plane passing thorough viewer orthogonal to surface: 0 -5 0 0
Projected surface onto the plane: -5 0 5, -5 0 -5, 5 0 -5, 5 0 5
to_2d of the projected plane: -5 1, -5 -1, 5 -1, 5 1
Area of to_2d'ed vertices: 20
I'm not sure how to_2d works but certainly not the way I hope it would. The computed area is 20 instead of the actual 100.
BTW, I've also begin to realize that this goal could be achieved by simple computing the angle between the viewing direction (V_c - V_v) and normal ofthe polyong. sin a * original_area should give the area.
To compute the centroid of your polygon you can use CGAL::centroid().
Then to construct your plane you can use the constructor of Plane_3 that takes a point and a normal.
After that you can project each point of your polygon using Plane_3::projection(), and then I'd propose to use to_2D() on those new points to get Point_2, and be able to use area_2().
I'm a newbie in mshadow, I can not understand why I got those outpus from the following code snippet:
TensorContainer<cpu, 2> lhs(Shape2(2, 3));
lhs = 1.0;
printf("%u %u\n", lhs.size(0), lhs.size(1));
printf("%u %u\n", lhs[0].shape_[0], lhs[0].shape_[1]);
printf("%u %u\n", lhs[0].size(0), lhs[0].size(1));
The output is:
2 3
3 4
3 3
Why are the second and third outputs those numbers? Because lhs[0] is one-dimensional, I think they should be exactly the same, i.e. 3 0. Could anyone tell me where I was wrong? Thanks in advance!
You are right, Tensor lhs[0] is one dimensional, but to answer you question first let me show what is going on under the hood. TensorContainer does not override the [] operator, instead it uses the one from the parent (which is Tensor), more precisely the following one is called:
MSHADOW_XINLINE Tensor<Device, kSubdim, DType> operator[](index_t idx) const {
return Tensor<Device, kSubdim, DType>(dptr_ + this->MemSize<1>() * idx,
shape_.SubShape(), stride_, stream_);
}
As can be seen it creates a new Tensor on a stack. And while for the most of the cases it will create generic N-dimensional Tensor, here for the 1-dimensional case it will create a special 1-dimensional Tensor.
Now ,when we have established what exactly is returned by the operator [], let's look on the fields of that class:
DType *dptr_;
Shape<1> shape_;
index_t stride_;
As can be seen the shape_ here has only 1 dimension! so there is no shape_1, instead by calling shape_1 it will return stride_(or part of it). Here is the modification to the Tensor constructor that you can try to run and see what is actually going on there:
MSHADOW_XINLINE Tensor(DType *dptr, Shape<1> shape,
index_t stride, Stream<Device> *stream)
: dptr_(dptr), shape_(shape), stride_(stride), stream_(stream) {
std::cout << "shape[0]: " << shape[0] << std::endl; // 3
std::cout << "shape[1]: " << shape[1] << std::endl; // 0, as expected
std::cout << "_shape[0]: " << shape_[0] << std::endl; // 3, as expected
std::cout << "_shape[1]: " << shape_[1] << std::endl; // garbage (4)
std::cout << "address of _shape[1]: " << &(shape_[1]) << std::endl;
std::cout << "address of stride: " << &(stride_) << std::endl;
}
and the output:
shape[0]: 3
shape[1]: 0
_shape[0]: 3
_shape[1]: 4
address of _shape[1]: 0x7fffa28ec44c
address of stride: 0x7fffa28ec44c
_shape1 and stride have both the same address (0x7fffa28ec44c).
I'm struggling to learn how to pack four seperate values into a single byte. I'm trying to get a hex output of 0x91 and the binary representation is supposed to be 10010001 but instead I'm getting outputs of: 0x1010001 and 16842753 respectively. Or is there a better way to do this?
uint8_t globalColorTableFlag = 1;
uint8_t colorResolution = 001;
uint8_t sortFlag = 0;
uint8_t sizeOfGlobalColorTable = 001;
uint32_t packed = ((globalColorTableFlag << 24) | (colorResolution << 16) | (sortFlag << 8) | (sizeOfGlobalColorTable << 0));
NSLog(#"%d",packed); // Logs 16842753, should be: 10010001
NSLog(#"0x%02X",packed); // Logs 0x1010001, should be: 0x91
Try the following:
/* packed starts at 0 */
uint8_t packed = 0;
/* one bit of the flag is kept and shifted to the last position */
packed |= ((globalColorTableFlag & 0x1) << 7);
/* three bits of the resolution are kept and shifted to the fifth position */
packed |= ((colorResolution & 0x7) << 4);
/* one bit of the flag is kept and shifted to the fourth position */
packed |= ((sortFlag & 0x1) << 3);
/* three bits are kept and left in the first position */
packed |= ((sizeOfGlobalColorTable & 0x7) << 0);
For an explanation about the relation between hexadecimal and binary digits see this answer: https://stackoverflow.com/a/17914633/4178025
For bitwise operations see: https://stackoverflow.com/a/3427633/4178025
packed = ((globalColorTableFlag & 1) << 7) +
((colorResolution & 0x7) << 4) +
((sortFlag & 1) << 3) +
((sizeOfGlobalColorTable & 0x7);
Is it expected that the following test should fail?
The test compares results of a 2D and a 3D AffineTransformation. Both are constructed to have unit scaling and zero offsets in the y and z direction, but to have non-zero and non-unity scaling and offset in the x direction. All other off-diagonal elements are zero. It is my belief that these transformations are identical in the x and y directions, and hence should produce identical results.
Furthermore I have found that the test passes if I use this Kernel:
using K = CGAL::Exact_predicates_exact_constructions_kernel;
Is it to be expected that the test passes if I use this Kernel? Should the test fail with either kernel or pass with either kernel?
TEST(TransformerTest, testCGALAffine) {
using K = CGAL::Exact_predicates_inexact_constructions_kernel;
using Float = typename K::FT;
using Transformation_2 = K::Aff_transformation_2;
using Transformation_3 = K::Aff_transformation_3;
using Point_2 = typename K::Point_2;
using Point_3 = typename K::Point_3;
double lowerCorner(17.005142946538115);
double upperCorner(91.940521484752139);
int resolution = 48;
double tmpScaleX((upperCorner - lowerCorner) / resolution);
Float scaleX(tmpScaleX);
Float zero(0);
Float unit(1);
// create a 2D voxel to world transform
Transformation_2 transformV2W_2(scaleX, zero, Float(lowerCorner),
zero, unit, zero,
unit);
// create it's inverse: a 2D world to voxel transform
auto transformW2V_2 = transformV2W_2.inverse();
// create a 3D voxel to world transform
Transformation_3 transformV2W_3(scaleX, zero, zero, Float(lowerCorner),
zero, unit, zero, zero,
zero, zero, unit, zero,
unit);
// create it's inverse: a 3D world to voxel transform
auto transformW2V_3 = transformV2W_3.inverse();
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 2; ++j) {
EXPECT_EQ(transformV2W_2.cartesian(i, j), transformV2W_3.cartesian(i, j)) << i << ", " << j;
EXPECT_EQ(transformW2V_2.cartesian(i, j), transformW2V_3.cartesian(i, j)) << i << ", " << j;
}
}
std::mt19937_64 rng(0);
std::uniform_real_distribution<double> randReal(0, resolution);
// compare the results of 2D and 3D transformations of random locations
for (int i = 0; i < static_cast<int>(1e4); ++i) {
Float x(randReal(rng));
Float y(randReal(rng));
auto world_2 = transformV2W_2(Point_2(x, y));
auto world_3 = transformV2W_3(Point_3(x, y, 0));
EXPECT_EQ(world_2.x(), world_3.x()) << world_2 << ", " << world_3;
auto voxel_2 = transformW2V_2(world_2);
auto voxel_3 = transformW2V_3(world_3);
EXPECT_EQ(voxel_2.x(), voxel_3.x()) << voxel_2 << ", " << voxel_3;
}
}
my code works the first time and when the loop start it stops calculating the numbers!
I want the program to ask the user to choose a material every time it finishes calculating the numbers. I used while (1!=2) { }
#include <iostream>
#include <stdio.h>
#include <math.h>
using namespace std;
float stress, strain, area;
double diameter;
long int F = 9900;
const float pi = 3.141593f;
int i = 0;
int main() {
char meterial;
cout << "This programm calculates the stress and strain of a rod under loads from 10000N to 20000N\n\n";
while (1!=2)
{
cout << "Choose the meterial of the rod\n\n";
cout << "S For STEEL\nA For ALUMINUM\nC For COPPER\nT For TITANIUM\n\n";
cin >> meterial;
switch (meterial)
{
case 's':
cout << "\nEnter the diameter of the rod in mm: ";
cin >> diameter;
area = (pi * diameter * diameter) / 4;
while (i <= 50)
{
stress = F / area;
strain = 200 / stress;
F = F + 100;
cout << "Load = " << F << " Stress = " << stress << " N/mm^2" << " Strain = " << strain << "\n";
i++;
}
break;
case 'a':
cout << "Enter the diameter of the rod in mm: ";
cin >> diameter;
area = (pi * diameter * diameter) / 4;
while (i <= 50)
{
stress = F / area;
strain = 69 / stress;
F = F + 100;
cout << "Load = " << F << " Stress = " << stress << " N/mm^2" << " Strain = " << strain << "\n";
i++;
}
break;
case 'c':
cout << "Enter the diameter of the rod in mm: ";
cin >> diameter;
area = (pi * diameter * diameter) / 4;
while (i <= 50)
{
stress = F / area;
strain = 117 / stress;
F = F + 100;
cout << "Load = " << F << " Stress = " << stress << " N/mm^2" << " Strain = " << strain << "\n";
i++;
}
break;
case 't':
cout << "Enter the diameter of the rod in mm: ";
cin >> diameter;
area = (pi * diameter * diameter) / 4;
while (i <= 50)
{
stress = F / area;
strain = 110.3 / stress;
F = F + 100;
cout << "Load = " << F << " Stress = " << stress << " N/mm^2" << " Strain = " << strain << "\n";
i++;
}
break;
default:
cout << "You entered a wrong character";
}
}
}
http://i.stack.imgur.com/do3qc.png
I don't see that you're resetting the value of i before the next call.
But you really should have that while loop (while (i <= 50)) in a function or method somewhere unless you have studied those yet.
The variable i is never re-initialized to zero. If you replace each
while (i <= 50)
statement in the cases for your switch statement with something like:
for (int i = 0; i <= 50; ++i)
and remove the i++; lines in each corresponding block, e.g.
case 's':
cout << "\nEnter the diameter of the rod in mm: ";
cin >> diameter;
area = (pi * diameter * diameter) / 4;
for (int i = 0; i <= 50; ++i) // while (i <= 50) <-- change
{
stress = F / area;
strain = 200 / stress;
F = F + 100;
cout << "Load = " << F << " Stress = " << stress << " N/mm^2" << " Strain = " << strain << "\n";
// i++; <-- remove
}
your code should do what you expect. You might consider replacing the while (1!=2) test with something like while(1) or for(;;), but only because those are more common idioms (your test will always evaluate to true so it's still just fine).
On Edit: one more thing - you never re-initialize F, but you modify it in your calculation. Each time you run through your switch statement, you're starting with a different initial value for F.