ld: library not found for -lglfw - c++

I well compiled/build the glfw library and after removed/replaced some functions in a file main.cc ( glfw 2 to version 3 ), it tells me this error
ld: library not found for -lglfw
clang: error: linker command failed with exit code 1 (use -v to see invocation)
This is the file :
/*
* Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors
* http://code.google.com/p/poly2tri/
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* * Neither the name of Poly2Tri nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <cstdlib>
#include </usr/local/include/GLFW/glfw3.h>
#include <time.h>
#include <fstream>
#include <string>
#include <sstream>
#include <algorithm>
#include <iterator>
#include <iostream>
using namespace std;
#include "../poly2tri/poly2tri.h"
using namespace p2t;
void Init();
void ShutDown(int return_code);
void MainLoop(const double zoom);
void Draw(const double zoom);
void DrawMap(const double zoom);
void ConstrainedColor(bool constrain);
double StringToDouble(const std::string& s);
double Random(double (*fun)(double), double xmin, double xmax);
double Fun(double x);
/// Dude hole examples
vector<Point*> CreateHeadHole();
vector<Point*> CreateChestHole();
float rotate_y = 0,
rotate_z = 0;
const float rotations_per_tick = .2;
/// Screen center x
double cx = 0.0;
/// Screen center y
double cy = 0.0;
/// Constrained triangles
vector<Triangle*> triangles;
/// Triangle map
list<Triangle*> map;
/// Polylines
vector< vector<Point*> > polylines;
/// Draw the entire triangle map?
bool draw_map = false;
/// Create a random distribution of points?
bool random_distribution = false;
template <class C> void FreeClear( C & cntr ) {
for ( typename C::iterator it = cntr.begin();
it != cntr.end(); ++it ) {
delete * it;
}
cntr.clear();
}
int main(int argc, char* argv[])
{
int num_points = 0;
double max, min;
double zoom;
if (argc != 5) {
cout << "-== USAGE ==-" << endl;
cout << "Load Data File: p2t filename center_x center_y zoom" << endl;
cout << "Example: ./build/p2t testbed/data/dude.dat 500 500 1" << endl;
return 1;
}
if(string(argv[1]) == "random") {
num_points = atoi(argv[2]);
random_distribution = true;
char* pEnd;
max = strtod(argv[3], &pEnd);
min = -max;
cx = cy = 0;
zoom = atof(argv[4]);
} else {
zoom = atof(argv[4]);
cx = atof(argv[2]);
cy = atof(argv[3]);
}
vector<p2t::Point*> polyline;
if(random_distribution) {
// Create a simple bounding box
polyline.push_back(new Point(min,min));
polyline.push_back(new Point(min,max));
polyline.push_back(new Point(max,max));
polyline.push_back(new Point(max,min));
} else {
// Load pointset from file
// Parse and tokenize data file
string line;
ifstream myfile(argv[1]);
if (myfile.is_open()) {
while (!myfile.eof()) {
getline(myfile, line);
if (line.size() == 0) {
break;
}
istringstream iss(line);
vector<string> tokens;
copy(istream_iterator<string>(iss), istream_iterator<string>(),
back_inserter<vector<string> >(tokens));
double x = StringToDouble(tokens[0]);
double y = StringToDouble(tokens[1]);
polyline.push_back(new Point(x, y));
num_points++;
}
myfile.close();
} else {
cout << "File not opened" << endl;
}
}
cout << "Number of constrained edges = " << polyline.size() << endl;
polylines.push_back(polyline);
Init();
/*
* Perform triangulation!
*/
double init_time = glfwGetTime();
/*
* STEP 1: Create CDT and add primary polyline
* NOTE: polyline must be a simple polygon. The polyline's points
* constitute constrained edges. No repeat points!!!
*/
CDT* cdt = new CDT(polyline);
/*
* STEP 2: Add holes or Steiner points if necessary
*/
string s(argv[1]);
if(s.find("dude.dat", 0) != string::npos) {
// Add head hole
vector<Point*> head_hole = CreateHeadHole();
num_points += head_hole.size();
cdt->AddHole(head_hole);
// Add chest hole
vector<Point*> chest_hole = CreateChestHole();
num_points += chest_hole.size();
cdt->AddHole(chest_hole);
polylines.push_back(head_hole);
polylines.push_back(chest_hole);
} else if (random_distribution) {
max-=(1e-4);
min+=(1e-4);
for(int i = 0; i < num_points; i++) {
double x = Random(Fun, min, max);
double y = Random(Fun, min, max);
cdt->AddPoint(new Point(x, y));
}
}
/*
* STEP 3: Triangulate!
*/
cdt->Triangulate();
double dt = glfwGetTime() - init_time;
triangles = cdt->GetTriangles();
map = cdt->GetMap();
cout << "Number of points = " << num_points << endl;
cout << "Number of triangles = " << triangles.size() << endl;
cout << "Elapsed time (ms) = " << dt*1000.0 << endl;
MainLoop(zoom);
// Cleanup
delete cdt;
// Free points
for(int i = 0; i < polylines.size(); i++) {
vector<Point*> poly = polylines[i];
FreeClear(poly);
}
ShutDown(0);
return 0;
}
void Init()
{
const int window_width = 800,
window_height = 600;
if (glfwInit() != GL_TRUE)
ShutDown(1);
// 800 x 600, 16 bit color, no depth, alpha or stencil buffers, windowed
if (glfwCreateWindow(window_width, window_height,"Poly2Tri - C++", NULL, NULL))
ShutDown(1);
glfwSwapInterval(1);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glClearColor(0.0, 0.0, 0.0, 0.0);
glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
}
void ShutDown(int return_code)
{
glfwTerminate();
exit(return_code);
}
void MainLoop(const double zoom)
{
// the time of the previous frame
double old_time = glfwGetTime();
// this just loops as long as the program runs
bool running = true;
while (running) {
// calculate time elapsed, and the amount by which stuff rotates
double current_time = glfwGetTime(),
delta_rotate = (current_time - old_time) * rotations_per_tick * 360;
old_time = current_time;
// escape to quit, arrow keys to rotate view
// Check if ESC key was pressed or window was closed
// z axis always rotates
rotate_z += delta_rotate;
// Draw the scene
if (draw_map) {
DrawMap(zoom);
} else {
Draw(zoom);
}
// swap back and front buffers
glfwPollEvents();
}
}
void ResetZoom(double zoom, double cx, double cy, double width, double height)
{
double left = -width / zoom;
double right = width / zoom;
double bottom = -height / zoom;
double top = height / zoom;
// Reset viewport
glLoadIdentity();
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
// Reset ortho view
glOrtho(left, right, bottom, top, 1, -1);
glTranslatef(-cx, -cy, 0);
glMatrixMode(GL_MODELVIEW);
glDisable(GL_DEPTH_TEST);
glLoadIdentity();
// Clear the screen
glClear(GL_COLOR_BUFFER_BIT);
}
void Draw(const double zoom)
{
// reset zoom
Point center = Point(cx, cy);
ResetZoom(zoom, center.x, center.y, 800, 600);
for (int i = 0; i < triangles.size(); i++) {
Triangle& t = *triangles[i];
Point& a = *t.GetPoint(0);
Point& b = *t.GetPoint(1);
Point& c = *t.GetPoint(2);
// Red
glColor3f(1, 0, 0);
glBegin(GL_LINE_LOOP);
glVertex2f(a.x, a.y);
glVertex2f(b.x, b.y);
glVertex2f(c.x, c.y);
glEnd();
}
// green
glColor3f(0, 1, 0);
for(int i = 0; i < polylines.size(); i++) {
vector<Point*> poly = polylines[i];
glBegin(GL_LINE_LOOP);
for(int j = 0; j < poly.size(); j++) {
glVertex2f(poly[j]->x, poly[j]->y);
}
glEnd();
}
}
void DrawMap(const double zoom)
{
// reset zoom
Point center = Point(cx, cy);
ResetZoom(zoom, center.x, center.y, 800, 600);
list<Triangle*>::iterator it;
for (it = map.begin(); it != map.end(); it++) {
Triangle& t = **it;
Point& a = *t.GetPoint(0);
Point& b = *t.GetPoint(1);
Point& c = *t.GetPoint(2);
ConstrainedColor(t.constrained_edge[2]);
glBegin(GL_LINES);
glVertex2f(a.x, a.y);
glVertex2f(b.x, b.y);
glEnd( );
ConstrainedColor(t.constrained_edge[0]);
glBegin(GL_LINES);
glVertex2f(b.x, b.y);
glVertex2f(c.x, c.y);
glEnd( );
ConstrainedColor(t.constrained_edge[1]);
glBegin(GL_LINES);
glVertex2f(c.x, c.y);
glVertex2f(a.x, a.y);
glEnd( );
}
}
void ConstrainedColor(bool constrain)
{
if (constrain) {
// Green
glColor3f(0, 1, 0);
} else {
// Red
glColor3f(1, 0, 0);
}
}
vector<Point*> CreateHeadHole() {
vector<Point*> head_hole;
head_hole.push_back(new Point(325, 437));
head_hole.push_back(new Point(320, 423));
head_hole.push_back(new Point(329, 413));
head_hole.push_back(new Point(332, 423));
return head_hole;
}
vector<Point*> CreateChestHole() {
vector<Point*> chest_hole;
chest_hole.push_back(new Point(320.72342,480));
chest_hole.push_back(new Point(338.90617,465.96863));
chest_hole.push_back(new Point(347.99754,480.61584));
chest_hole.push_back(new Point(329.8148,510.41534));
chest_hole.push_back(new Point(339.91632,480.11077));
chest_hole.push_back(new Point(334.86556,478.09046));
return chest_hole;
}
double StringToDouble(const std::string& s)
{
std::istringstream i(s);
double x;
if (!(i >> x))
return 0;
return x;
}
double Fun(double x)
{
return 2.5 + sin(10 * x) / x;
}
double Random(double (*fun)(double), double xmin = 0, double xmax = 1)
{
static double (*Fun)(double) = NULL, YMin, YMax;
static bool First = true;
// Initialises random generator for first call
if (First)
{
First = false;
srand((unsigned) time(NULL));
}
// Evaluates maximum of function
if (fun != Fun)
{
Fun = fun;
YMin = 0, YMax = Fun(xmin);
for (int iX = 1; iX < RAND_MAX; iX++)
{
double X = xmin + (xmax - xmin) * iX / RAND_MAX;
double Y = Fun(X);
YMax = Y > YMax ? Y : YMax;
}
}
// Gets random values for X & Y
double X = xmin + (xmax - xmin) * rand() / RAND_MAX;
double Y = YMin + (YMax - YMin) * rand() / RAND_MAX;
// Returns if valid and try again if not valid
return Y < fun(X) ? X : Random(Fun, xmin, xmax);
}
This is a file test of a library ( for triangulation in c++/opengl)
I used a lot a line compilation like :
cc -o main main.cc -lglfw -framework Cocoa -framework OpenGL -framework IOKit -framework CoreVideo
g++ main.cpp -o main -lglwf
etc..
Someone can help me ?
PS : I'm on MAC OS X

Did you try using -lglfw3? You are using glfw3, I would try that

In my case after building glfw i've got file libglfw.3.dylib and when build my client code i've come with the similar link error. Solution was to rename dylib file to lglfw.3.dylib. I saw that previously for different libs, when cmake for some reason provide different lib name than expected. Hope that will help someone)

Related

How to fix vertical artifact lines in a vertex array in SFML, WITH pixel perfect zoom/move?

I have been working on a 2D top-down game solely in SFML and C++, that has a tilemap. I cannot rid the tilemap of vertical line artifacts when zooming in and out or moving the render view at different zoom levels. I attached an image below of the problem; circled in red.
[edit]
There are a lot of factors that make this bug inconsistent.
If I use a tile_atlas from only one tile, there is no artifacts. If I map each texture to a tile a.k.a not using vertex arrays; I did not see any artifacts but it is anywhere from 10x to 15x slower with the same number of tiles on the screen. I have tried finding zoom levels that don't cause artifacts, and there are some. but the levels are almost random and makes zoom in and out, not smooth and choppy.
I have tried numerous tutorials and forum "fixes" that have not completely worked. I have completely rewrote the underlying tile engine 4 separate times to no avail.
https://en.sfml-dev.org/forums/index.php?topic=15747.0
topic=14504
topic=5952
topic=13637.15
https://www.sfml-dev.org/tutorials/2.5/graphics-view.php
https://www.binpress.com/creating-city-building-game-with-sfml/
https://www.sfml-dev.org/tutorials/2.5/graphics-vertex-array.php
[edit]
I have read the Terreria scaling issue, the fix to make extra large textures then scale, or multiple textures, one for each zoom level. seem exhaustive. I am looking for a programmatic way of achieving the scaling correctly.
This is post is my last attempt to fix the code, otherwise I will need to change languages.
I believe the main issue comes from the zoom in/out functions of the program.
I have tried many, variations/attempt to get this to work +0.5f offset,+0.375f offset, not pixel perfect
if (sf::Keyboard::isKeyPressed(sf::Keyboard::E))
{
float zoom_in = 0.995f;
float nz = last_sq * zoom_in;
nz = std::floor(nz);
float now = nz / last_sq;
if (nz <= 10)
continue;
last_sq = nz;
std::cout << now << std::endl;
cam.zoom(now);
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::W))
{
cam.move(0.f, -0.02f);
float x = cam.getCenter().x;
float y = cam.getCenter().y;
x = std::floor(x);
y = std::floor(y);
//std::cout << "x: " << x << "\ty: " << y << std::endl;
cam.setCenter(x, y);
}
Here is the entire code.
main.cpp
#include "chunk_map.h"
#include "tile_atlas.h"
#include <vector>
//#include "main.h"
#include "map.h"
#include <iostream>
#include <SFML/Graphics/RenderWindow.hpp>
#include <SFML/Graphics/View.hpp>
#include <SFML/Window/Event.hpp>
#include <SFML/Window/Keyboard.hpp>
#include "animation_handler.h"
int main(int argc, char* argv[])
{
sf::RenderWindow app(sf::VideoMode(600, 600), "Tilemap Example");
// Hard set fps to monitor refresh rate.
// textures to load.
/*text_mgr.loadTexture("grass", "grass.png");
text_mgr.loadTexture("high_grass", "high_grass.png");
Animation staticAnim(0, 0, 1.0f);
tileAtlas["grass"] = Tile(32, 1, text_mgr.getRef("grass"),{ staticAnim },
TileType::GRASS, 50, 0, 1);
tileAtlas["high_grass"] = Tile(32, 1, text_mgr.getRef("high_grass"),{ staticAnim },
TileType::HIGH_GRASS, 100, 0, 1);*/
//Map map;
//map.load(50, 50, tileAtlas);
#ifdef NDEBUG
app.setVerticalSyncEnabled(true);
std::cout << "#################\n";
#endif // DEBUG
//app.setVerticalSyncEnabled(true);
sf::View cam = app.getDefaultView();
tile_atlas atlas = tile_atlas();
std::vector<chunk_map> map;
for (int x = 0; x < 5; x++)
{
for (int y = 0; y < 5; y++)
{
map.push_back(chunk_map());
map.back().set_texture(atlas.get_atlas());
map.back().set_position(10 * x, 10 * y, 10 * (x + 1), 10 * (y + 1));
map.back().load_tiles();
}
}
sf::Clock clock;
int checked = 0;
int last_sq = 600;
while (app.isOpen())
{
//sf::Time elapsed = clock.restart();
//float dt = elapsed.asSeconds();
sf::Event eve;
while (app.pollEvent(eve))
if (eve.type == sf::Event::Closed)
app.close();
if (sf::Keyboard::isKeyPressed(sf::Keyboard::P))
std::cout << "view x: " << cam.getSize().x << "\tview y: " << cam.getSize().y << std::endl;
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Q))
{
float zoom_out = 1.005f;
float nz = last_sq * zoom_out;
nz = std::ceil(nz);
float now = nz / last_sq;
last_sq = nz;
std::cout << now << std::endl;
cam.zoom(now);
//float x = cam.getCenter().x;
//float y = cam.getCenter().y;
//x = std::floor(x);
//y = std::floor(y);
////std::cout << "x: " << x << "\ty: " << y << std::endl;
//cam.setCenter(x, y);
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::E))
{
float zoom_in = 0.995f;
float nz = last_sq * zoom_in;
nz = std::floor(nz);
float now = nz / last_sq;
if (nz <= 10)
continue;
last_sq = nz;
std::cout << now << std::endl;
cam.zoom(now);
//float x = cam.getCenter().x;
//float y = cam.getCenter().y;
//x = std::floor(x);
//y = std::floor(y);
////std::cout << "x: " << x << "\ty: " << y << std::endl;
//cam.setCenter(x, y);
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::W))
{
cam.move(0.f, -0.02f);
float x = cam.getCenter().x;
float y = cam.getCenter().y;
x = std::floor(x);
y = std::floor(y);
//std::cout << "x: " << x << "\ty: " << y << std::endl;
cam.setCenter(x, y);
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::A))
{
cam.move(-0.02f, 0.f);
float x = cam.getCenter().x;
float y = cam.getCenter().y;
x = std::floor(x);
y = std::floor(y);
//std::cout << "x: " << x << "\ty: " << y << std::endl;
cam.setCenter(x, y);
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::S))
{
cam.move(0.f, 0.02f);
float x = cam.getCenter().x;
float y = cam.getCenter().y;
x = std::ceil(x);
y = std::ceil(y);
//std::cout << "x: " << x << "\ty: " << y << std::endl;
cam.setCenter(x, y);
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::D))
{
cam.move(0.02f, 0.f);
float x = cam.getCenter().x;
float y = cam.getCenter().y;
x = std::ceil(x);
y = std::ceil(y);
//std::cout << "x: " << x << "\ty: " << y << std::endl;
cam.setCenter(x, y);
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Right))
{
sf::Time elapsed = clock.getElapsedTime();
float t = elapsed.asSeconds();
int time = std::floor(t);
if (checked < time)
{
checked = time;
cam.move(0.01f, 0.f);
float x = cam.getCenter().x;
float y = cam.getCenter().y;
x = std::ceil(x);
y = std::ceil(y);
std::cout << "x: " << x << "\ty: " << y << std::endl;
cam.setCenter(x, y);
}
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Escape))
app.close();
app.setView(cam);
#ifdef _DEBUG
app.clear();
#endif // DEBUG
//map.draw(app, dt);
for (int i = 0; i < 25; i++)
{
app.draw(map.at(i));
}
app.display();
}
}
chunk_map.h
#pragma once
#include <SFML/Graphics/Drawable.hpp>
#include <SFML/Graphics/Texture.hpp>
#include <SFML/Graphics/VertexArray.hpp>
#include <vector>
class chunk_map : public sf::Drawable
{
private:
//change values of these to match your needs and improve performance
enum { tilesize = 32, chunksize = 32};
//tile size float
float tile_size_float = 32.0f;
// Draw chunk
virtual void draw(sf::RenderTarget& target, sf::RenderStates states)const;
// texture for chunk
sf::Texture m_texture;
// chunk dimensions
int tiles_per_chunk_x;
int tiles_per_chunk_y;
//start x and y and ending x and y scaled to tile size. a.k.a.
// 1,1 = tile 1,1. 10,10, equals tile 10,10
int chunk_start_x;
int chunk_start_y;
int chunk_end_x;
int chunk_end_y;
// Vertex array of positions of tiles in chunk
std::vector<std::vector<sf::VertexArray> > m_chunks;
// Append tiles.
void append_tile(int gx, int gy, sf::VertexArray& garr);
public:
chunk_map();
~chunk_map();
void load_tiles();
void set_texture(sf::Texture);
void set_position(int chunk_start_x, int chunk_start_y,
int chunk_end_x, int chunk_end_y);
};
chunk_map.cpp
#include "chunk_map.h"
#include <SFML/Graphics/RenderTarget.hpp>
#include <SFML/System/Vector2.hpp>
#include <SFML/Graphics/Vertex.hpp>
chunk_map::chunk_map()
{
}
chunk_map::~chunk_map()
{
}
void chunk_map::load_tiles()
{
/*
Tile loading this is were the tiles are added to the Quadrantics of the tilemap.
this is the entire chunk_map loop
*/
if ((chunk_end_x * chunk_end_y) == 0)//empty map - possibly forgotten to fill data struct
{
//to stop displaying at all after failed loading:
tiles_per_chunk_x = 0;
tiles_per_chunk_y = 0;
m_chunks.clear();
return;
}
chunk_map::tiles_per_chunk_x = (chunk_end_x / chunksize) + 1;
chunk_map::tiles_per_chunk_y = (chunk_end_y / chunksize) + 1;
m_chunks.assign(tiles_per_chunk_x, std::vector<sf::VertexArray>(tiles_per_chunk_y, sf::VertexArray(sf::Quads)));//ready up empty 2d arrays
for (int iy = chunk_start_y; iy < chunk_end_y; ++iy)
{
for (int ix = chunk_start_x; ix < chunk_end_x; ++ix)
{
append_tile(ix, iy, m_chunks[ix / chunksize][iy / chunksize]);
}
}
}
void chunk_map::append_tile(int gx, int gy, sf::VertexArray& garr)
{
/*
This is the specific tile vertex, broken from the other function to decrease complexitity.
*/
int tile_selection_index_x = rand() % 2;
int tile_selection_index_y = 0;
float f_tx = tile_selection_index_x * tile_size_float;
float f_ty = tile_selection_index_y * tile_size_float;
sf::Vertex ver;
//____________________________________________________________________________________________________________
ver.position = sf::Vector2f(gx * tile_size_float, gy * tile_size_float);
//texture in position of text atlas
//top left corner
//ver.texCoords = sf::Vector2f( 0.f, 0.f);
ver.texCoords = sf::Vector2f(f_tx, f_ty);
garr.append(ver);
//____________________________________________________________________________________________________________
ver.position = sf::Vector2f(gx * tile_size_float + tile_size_float, gy * tile_size_float);
//texture in position of text atlas
//top right corner
//ver.texCoords = sf::Vector2f( tile_size_float, 0.f);
ver.texCoords = sf::Vector2f(f_tx + tile_size_float, f_ty);
garr.append(ver);
//____________________________________________________________________________________________________________
ver.position = sf::Vector2f(gx * tile_size_float + tile_size_float, gy * tile_size_float + tile_size_float);
//texture in position of text atlas
//bottom right corner
//ver.texCoords = sf::Vector2f( tile_size_float, tile_size_float);
ver.texCoords = sf::Vector2f(f_tx + tile_size_float, f_ty + tile_size_float);
garr.append(ver);
//____________________________________________________________________________________________________________
ver.position = sf::Vector2f(gx * tile_size_float, gy * tile_size_float + tile_size_float);
//texture in position of text atlas
//bottom left corner
//ver.texCoords = sf::Vector2f( 0.f, tile_size_float);
ver.texCoords = sf::Vector2f(f_tx, f_ty + tile_size_float);
garr.append(ver);
}
void chunk_map::set_texture(sf::Texture t)
{
/*
Sets the texture data for this chunk map from the texture atlas.
*/
m_texture = t;
// TODO test this feature
// Attempt to optimize tearing on zooming to a different view.
//m_texture.setSmooth(true);
}
void chunk_map::set_position(int chunk_start_x, int chunk_start_y,
int chunk_end_x, int chunk_end_y)
{
/*
Initialize the accordinates of the start of the chunk_map to the end.
*/
chunk_map::chunk_start_x = chunk_start_x;
chunk_map::chunk_start_y = chunk_start_y;
chunk_map::chunk_end_x = chunk_end_x;
chunk_map::chunk_end_y = chunk_end_y;
}
void chunk_map::draw(sf::RenderTarget& target, sf::RenderStates states)const
{
/*
The actual draw call to this specific chunk_map
*/
// position variables for this draw.
int left = 0;
int right = 0;
int top = 0;
int bottom = 0;
//get top left point of view
sf::Vector2f temp = target.getView().getCenter() - (target.getView().getSize() / 2.f);
//get top left point of view
left = static_cast<int>(temp.x / (chunksize * tilesize));
top = static_cast<int>(temp.y / (chunksize * tilesize));
//get bottom right point of view
temp += target.getView().getSize();
right = 1 + static_cast<int>(temp.x / (chunksize * tilesize));
bottom = 1 + static_cast<int>(temp.y / (chunksize * tilesize));
//clamp these to fit into array bounds:
left = std::max(0, std::min(left, tiles_per_chunk_x));
top = std::max(0, std::min(top, tiles_per_chunk_y));
right = std::max(0, std::min(right, tiles_per_chunk_x));
bottom = std::max(0, std::min(bottom, tiles_per_chunk_y));
//set texture and draw visible chunks:
states.texture = &m_texture;
for (int ix = left; ix < right; ++ix)
{
for (int iy = top; iy < bottom; ++iy)
{
target.draw(m_chunks[ix][iy], states);
}
}
}
tile_atlas.h
#pragma once
#include <SFML/Graphics/Texture.hpp>
class tile_atlas
{
private:
sf::Texture atlas_texture;
public:
tile_atlas();
~tile_atlas();
sf::Texture& get_atlas();
};
tile_atlas.cpp
#include "tile_atlas.h"
#include <iostream>
#include <string>
tile_atlas::tile_atlas()
{
std::string file_string = "tilemap_test.png";
if (!atlas_texture.loadFromFile(file_string))
{
std::cout << "Failed loading file: " << file_string << std::endl;
exit(1);
}
}
tile_atlas::~tile_atlas()
{
}
sf::Texture& tile_atlas::get_atlas()
{
return atlas_texture;
}
I am trying to fix this code to remove vertical artifacts so the above image will always look like this no matter if moving the view or zooming in/out.
[code for answer]
Using #Mario's answer this is the code I wrote (at the bottom of main.cpp) that completely fixed the artifacts.
here is a great link showing an example.
https://www.sfml-dev.org/tutorials/2.5/graphics-draw.php#off-screen-drawing
#ifdef _DEBUG
app.clear();
#endif // DEBUG
//map.draw(app, dt);
/*-----------------------------------------------------------*/
// Draw the texture
//rt.clear();
rt.draw(map.at(0));
rt.display();
if (cam.getSize().x < 500)
{
rt.setSmooth(false);
}
else
{
rt.setSmooth(true);
}
//// get the target texture (where the stuff has been drawn)
const sf::Texture& texture = rt.getTexture();
sf::Sprite sprite(texture);
app.draw(sprite);
//app.draw(map.at(0));
/*-----------------------------------------------------------*/
app.display();
Simple, yet effective:
Render your pixels 1:1 without scaling to a render texture and then upscale that instead.
Might be a bit tricky to determine the correct position, zoom, etc. but it can be done.

Determining whether a user specified point is inside a 2d polygon

I've done some research and there are many methods to doing this if the vertices and points are predetermined as seen here. However in my case, everything is specified by the user. The code I have put together (with the help of others), allows the user to create the polygon, and place points. I wrote functions to try and create vectors from the point to the vertices and then compute the angle. If it comes to 360 it should be inside and it should be colored green. Else it should be outside and red.
This is what I've been working on, but I cant seem to figure it out:
(Edit: Included my entire code)
GLint vert[100][2];
int width = 400, height = 600, n = 0, m = 0, type = GL_LINE_STRIP, v;
bool rubberbanding = false;
bool closed = false;
double testx, testy;
bool isitin;
double dotp(double x1, double y1, double x2, double y2) {
double a;
a = (x1 * x2) + (y1 * y2);
return a;
}
double mag(double x1, double y1, double x2, double y2) {
double a;
double x = (x2 - x1);
double y = (y2 - y1);
a = sqrt((x*x) + (y*y));
return a;
}
bool inpoly(int numv, GLint vx[][2], GLint vy[][2], double tx, double ty) {
double angle = 0.0;
int n = 0;
while (n != numv) {
//vector from point to vertex
double newv1x = vx[n][0] - tx;
double newv1y = vy[n][1] - ty;
double magv1 = mag(tx, ty, vx[n][0], vy[n][1]); //magnitude of vector
//vector from point to next vertex
double newv2x = vx[n + 1][0] - tx;
double newv2y = vy[n + 1][1] - ty;
double magv2 = mag(tx, ty, vx[n+1][0], vy[n+1][1]);//magnitude of vector
//dot product between the two vectors
double dp = dotp(newv1x, newv1y, newv2x, newv2y);
//angle between two vectors
double vang = acos(dp / (magv1*magv2));
angle += vang;
n++;
}
//vector from point to last vertex
double newv1x = vx[numv][0] - tx;
double newv1y = vy[numv][1] - ty;
double magv1 = mag(tx, ty, vx[numv][0], vy[numv][1]); //magnitude of vector
//vector from point to first vertex
double newv2x = vx[0][0] - tx;
double newv2y = vy[0][1] - ty;
double magv2 = mag(tx, ty, vx[0][0], vy[0][1]);//magnitude of vector
//dot product between the two vectors
double dp = dotp(newv1x, newv1y, newv2x, newv2y);
//angle between two vectors
double vang = acos(dp / (magv1*magv2));
angle += vang;
if (angle == 360.0) return true;
return false;
}
void display(){
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1, 1, 0);
glBegin(closed ? GL_LINE_LOOP : GL_LINE_STRIP);
for(int i = 0; i < m; i++){
glVertex2iv(vert[i]);
}
glEnd();
/*
glColor3f(0, 0, 1);
glBegin(GL_POINTS);
for (int i = m; i < n; i++) {
glVertex2iv(vert[i]);
}
*/
isitin = inpoly(m, vert, vert, testx, testy);
if (isitin == true) {
glColor3f(0, 1, 0);
glBegin(GL_POINTS);
for (int i = m; i < n; i++) {
glVertex2iv(vert[i]);
}
}
else {
glColor3f(1, 0, 0);
glBegin(GL_POINTS);
for (int i = m; i < n; i++) {
glVertex2iv(vert[i]);
}
}
glEnd();
glutSwapBuffers();
glutPostRedisplay();
}
void keyboard(unsigned char key, int x, int y){
switch(key){
case 'r': n = 0; m = 0; closed = false; break;
case 'c': closed = true; break;
}
glutPostRedisplay();
}
int findVertex(int x, int y){
int dx, dy;
for(int i = 0; i < n; i++){
dx = vert[i][0] - x;
dy = vert[i][1] - y;
if(dx*dx + dy*dy < 16) return i;
}
return - 1;
}
void mousemove(int x, int y)
{
testx = x;
testy = height - 1 - y;
}
void mouse(int button, int state, int x, int y){
switch(button){
case GLUT_LEFT_BUTTON:
if(state == GLUT_DOWN){
if (n < 100) {
v = n++;
vert[v][0] = x;
vert[v][1] = height - 1 - y;
// n++;
rubberbanding = true;
glutPostRedisplay();
if (!closed) m = n;
}
}
else{
rubberbanding = false;
}
break;
}
}
void motion(int x, int y){
if(rubberbanding){
vert[v][0] = x;
vert[v][1] = height - 1 - y;
glutPostRedisplay();
}
}
void main(int argc, char** argv){
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGB|GLUT_DOUBLE);
glutInitWindowSize(width,height);
glutInitWindowPosition(50,100);
glutCreateWindow("Project 3");
glClearColor(0.0,0.0,0.0,0.0);
glColor3f( 1, 1, 0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0, width, 0, height);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glutDisplayFunc(display);
glutKeyboardFunc(keyboard);
glutMouseFunc(mouse);
glutPassiveMotionFunc(mousemove);
glutMotionFunc(motion);
glutMainLoop();
}
When I run the program in Visual Studio, I can draw the polygon, and I can specify
points, but for some reason all the points appear red. If anyone has any ideas on how to fix this, it would be greatly appreciated.
Probably your error is that acos returns in radians, and you're testing if the sum equals 360 degrees.
Also, you shouldn't compare doubles that way, since that calculation is probably adding rounding error in each sum. See here for more information.

How to draw a Bezier curve with C++ in OpenGL using floating point values

I am trying to draw a Bezier curve in OpenGL using floating point values. I have tried using many different code examples. My current code below, runs ,but does not show the curve on screen. The usual way to draw Bezier curves are with integer values, which means using the GLUORTHO2D() function for drawing the curve. But I want to draw a curve using floating point values. Such as x range(-1,1) and y range(-1,1).
like if x=(500) then consider it (-1 to 1) and if y=(800) then consider it (-1,1).
I have already tried using integer values and it worked for me. my code using integer values is below:
#include <GL/glut.h>
#include <math.h>
#include <stdio.h>
#define CTRL_COUNT 100
int ctrlPointsCount;
int ctrlPointsX[CTRL_COUNT], ctrlPointsY[CTRL_COUNT];
int X1[3]={20,25,20}, Y1[3]={5,24,38}; //first point(x1[0],y1[0]) second(x1[1],y1[1]) third(x1[2],y1[2])
void myInit()
{
glClearColor(0.0,0.0,0.0,0.0);
glColor3f(1.0,0.0,0.0);
glPointSize(8.0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0,128.0,0.0,96.0);
}
//p(t)=(1-t)^3*p0+3t(1-t)^2*p1+3t^2(1-t)p2+t^3p3
float getNextBezierPointX(float t)
{
float x=0.0;
for(int i=0; i<ctrlPointsCount; i++)
{
int c;
if(i==0 || i==ctrlPointsCount-1)
c = 1;
else
{
c = ctrlPointsCount-1;
}
x += c * pow(t, i) * pow(1-t, ctrlPointsCount-1-i) * ctrlPointsX[i];
}
return x;
}
float getNextBezierPointY(float t)
{
float y=0.0;
for(int i=0; i<ctrlPointsCount; i++)
{
int c;
if(i==0 || i==ctrlPointsCount-1)
c = 1;
else
{
c = ctrlPointsCount-1;
}
y += c * pow(t, i) * pow(1-t, ctrlPointsCount-1-i) * ctrlPointsY[i];
}
return y;
}
void drawline()
{
// draw control points using red color
for(int i=0; i < 3; i++)
{
glBegin(GL_POINTS);
glVertex2i(ctrlPointsX[i], ctrlPointsY[i]);
glEnd();
glFlush();
}
// draw bezier curve using control poitns by calculating next points using cubic bezier curve formula
float oldX=ctrlPointsX[0], oldY=ctrlPointsY[0];
for(double t = 0.0;t <= 1.0; t += 0.01) {
float x = getNextBezierPointX(t);
float y = getNextBezierPointY(t);
//glColor3f(1.0,t,1.0);
glColor3f(1.0,1.0,1.0);
glBegin(GL_LINES);
glVertex2f(oldX, oldY);
glVertex2f(x, y);
glEnd();
glFlush();
oldX = x;
oldY = y;
}
}
void myDisplay()
{
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1.0,0.0,0.0);
ctrlPointsCount=3;
for(int i=0;i<3;i++)
{
ctrlPointsX[i] = X1[i];
ctrlPointsY[i] = Y1[i];
}
drawline();
glFlush();
}
int main(int argc, char *argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB);
glutInitWindowSize(640,480);
glutInitWindowPosition(100,150);
glutCreateWindow("Bezier Curve");
glutDisplayFunc(myDisplay);
myInit();
glutMainLoop();
return 0;
}
But when i tried using floating point values , it does not work for me. It does not show the curved line on screen. My code using floating point values is below:
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <GL/glut.h>
using namespace std;
#define CTRL_COUNT 100
int ctrlPointsCount;
int ctrlPointsX[CTRL_COUNT], ctrlPointsY[CTRL_COUNT];
double X1[3] = { 0.26015037593985, 0.43609022556391, 0.6 }, Y1[3] = { 0.946875, 0.884375, 0.946875 };
//Initializes 3D rendering
void initRendering() {
glEnable(GL_DEPTH_TEST);
}
float getNextBezierPointX(float t)
{
float x = 0.0;
for (int i = 0; i<ctrlPointsCount; i++)
{
int c;
if (i == 0 || i == ctrlPointsCount - 1)
c = 1;
else
{
c = ctrlPointsCount - 1;
}
x += c * pow(t, i) * pow(1 - t, ctrlPointsCount - 1 - i) * ctrlPointsX[i];
}
return x;
}
float getNextBezierPointY(float t)
{
float y = 0.0;
for (int i = 0; i<ctrlPointsCount; i++)
{
int c;
if (i == 0 || i == ctrlPointsCount - 1)
c = 1;
else
{
c = ctrlPointsCount - 1;
}
y += c * pow(t, i) * pow(1 - t, ctrlPointsCount - 1 - i) * ctrlPointsY[i];
}
return y;
}
void drawline()
{
// draw control points using red color
for (int i = 0; i < 3; i++)
{
glBegin(GL_POINTS);
glVertex2i(ctrlPointsX[i], ctrlPointsY[i]);
glEnd();
glFlush();
}
// draw bezier curve using control poitns by calculating next points using cubic bezier curve formula
float oldX = ctrlPointsX[0], oldY = ctrlPointsY[0];
for (double t = 0.0; t <= 1.0; t += 0.01)
{
float x = getNextBezierPointX(t);
float y = getNextBezierPointY(t);
//glColor3f(1.0,t,1.0);
glColor3f(1.0, 1.0, 1.0);
glBegin(GL_LINES);
glVertex2f(oldX, oldY);
glVertex2f(x, y);
glEnd();
glFlush();
oldX = x;
oldY = y;
}
}
//Called when the window is resized
void handleResize(int w, int h) {
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0, (double)w / (double)h, 1.0, 200.0);
}
float _angle = 0.0;
float _cameraAngle = 0.0;
float _ang_tri = 0.0;
//Draws the 3D scene
void drawScene() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity(); //Reset the drawing perspective
ctrlPointsCount = 3;
for (int i = 0; i<3; i++)
{
ctrlPointsX[i] = X1[i];
ctrlPointsY[i] = Y1[i];
}
drawline();
glutSwapBuffers();
}
void update(int value) {
_angle += 2.0f;
if (_angle > 360) {
_angle -= 360;
}
_ang_tri += 2.0f;
if (_ang_tri > 360) {
_ang_tri -= 360;
}
glutPostRedisplay(); //Tell GLUT that the display has changed
//Tell GLUT to call update again in 25 milliseconds
glutTimerFunc(25, update, 0);
}
int main(int argc, char** argv) {
//Initialize GLUT
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(1331, 641);
glutInitWindowPosition(0, 0);
//Create the window
glutCreateWindow("Our cg project");
initRendering();
//Set handler functions
glutDisplayFunc(drawScene);
glutReshapeFunc(handleResize);
glutTimerFunc(25, update, 0); //Add a timer
glClearColor(0.0, 0.7, 1.5,0.0);
glutMainLoop();
return 0;
}
The problem is this here:
int ctrlPointsX[CTRL_COUNT], ctrlPointsY[CTRL_COUNT];
double X1[3] = { 0.26015037593985, 0.43609022556391, 0.6 }, Y1[3] = {0.946875, 0.884375, 0.946875 };
for (int i = 0; i<3; i++)
{
ctrlPointsX[i] = X1[i];
ctrlPointsY[i] = Y1[i];
}
ctrlPointsX and ctrlPointsYcan only hold integer values. So when you do ctrlPointsX[i] = X1[i] and ctrlPointsY[i] = Y1[i] you are converting the floats to integers, which will round them down. So all your controlPoints will be 0.
You have to declare the controlPoints arrays as type double too:
double ctrlPointsX[CTRL_COUNT], ctrlPointsY[CTRL_COUNT];
double X1[3] = { 0.26015037593985, 0.43609022556391, 0.6 }, Y1[3] = {0.946875, 0.884375, 0.946875 };
This should fix your problem.

Radial Tree layout algorithm

I have implemented a tree data structure in which every node holds (recursivly) a list of pointers to it's children.
I am trying to calculate the (x,y) coordinates for visualizing the tree.
I went through this article:
http://gbook.org/projects/RadialTreeGraph.pdf
Cut I can't figure out how to gest past the first level, i.e This is what I have written so far:
for (int i = 0; i < GetDepth()+1; i++)
{
if (i == 0)
{
GetNodesInDepth(i).at(0)->SetXRadial(MIDDLE(m_nWidth));
GetNodesInDepth(i).at(0)->SetYRadial(MIDDLE(m_nHeight));
continue;
}
double dNodesInDepth = GetNodesInDepth(i).size();
double dAngleSpace = 2 * PI / dNodesInDepth;
for (int j = 0; j < dNodesInDepth; j++)
{
Node * pCurrentNode = GetNodesInDepth(i).at(j);
pCurrentNode->SetXRadial((SPACING * i) * qCos(j * dAngleSpace) + MIDDLE(m_nWidth));
pCurrentNode->SetYRadial((SPACING * i) * qSin(j * dAngleSpace) + MIDDLE(m_nHeight));
pCurrentNode->m_dAngle = dAngleSpace * j;
if (pCurrentNode->IsParent())
{
//..(I'm stuck here)..//
}
}
}
I am not sure how to calculate the limits, bisectors etc.
this is what my drawer did so far:
which is obviously not what i'm looking for since the second (0 based) level.
I have access to every info that I need in order to obtain what I'm looking for.
Probably by now you figured it out yourself. If not, here
double dNodesInDepth = GetNodesInDepth(i).size();
double dAngleSpace = 2 * PI / dNodesInDepth;
you're setting the angle space to PI (180 degreees) at your second level, as there are only two nodes at that level, dNodesInDepth = 2. That's why after drawing the node 20, the node 30 is 180 degrees away. That method would be fine for very dense trees because that angle will be small. But in your case you want to keep the angle as close as possible to the angle of the parent. So I suggest you get the angle of the parent for nodes at level 2 and higher, and spread the children so they have an angle space of sibilingAngle = min(dAngleSpace, PI/10). So the first child will have the exact angle of the parent, and the remaining children are sibilingAngle away from one another. You get the idea and probably come with a better method. I'm using min in case you have got too many nodes at that level you want to squeeze the nodes closer to each other.
The article you've linked to, uses a solution that is illustrated in Figure 2 – Tangent and bisector limits for directories. I don't like that method much because if you determine the absolute angle of the children rather than relative to the parent you can have a simpler/cleaner solution that does exactly what that method tries to do with so many operations.
Update:
The following code produces this image:
I think you can easily figure out how to center the child nodes and etc.
#include <cairo/cairo.h>
#include <math.h>
#include <vector>
using namespace std;
class Node {
public:
Node() {
parent = 0;
angle = 0;
angleRange = 2*M_PI;
depth = 0;
}
void addChildren(int n) {
for (int i=0; i<n; i++) {
Node* c = new Node;
c->parent = this;
c->depth = depth+1;
children.push_back(c);
}
}
vector<Node*> children;
float angle;
float angleRange;
Node* parent;
int depth;
int x, y;
};
void rotate(float x, float y, float angle, float& nx, float& ny) {
nx = x * cos(angle) - y * sin(angle);
ny = x * sin(angle) + y * cos(angle);
}
void draw(Node* root, cairo_t *cr) {
if (root->parent == 0) {
root->x = root->y = 300;
cairo_arc(cr, root->x, root->y, 3, 0, 2 * M_PI);
}
int n = root->children.size();
for (int i=0; i<root->children.size(); i++) {
root->children[i]->angle = root->angle + root->angleRange/n * i;
root->children[i]->angleRange = root->angleRange/n;
float x, y;
rotate(40 * root->children[i]->depth, 0, root->children[i]->angle, x, y);
root->children[i]->x = 300+x;
root->children[i]->y = 300+y;
cairo_move_to(cr, root->x, root->y);
cairo_line_to(cr, root->children[i]->x, root->children[i]->y);
cairo_set_source_rgb(cr, 0, 0, 0);
cairo_stroke(cr);
cairo_arc(cr, 300+x, 300+y, 3, 0, 2 * M_PI);
cairo_set_source_rgb(cr, 1, 1, 1);
cairo_stroke_preserve(cr);
cairo_set_source_rgb(cr, 0, 0, 0);
cairo_fill(cr);
draw(root->children[i], cr);
}
}
int main(void) {
Node root;
root.addChildren(4);
root.children[0]->addChildren(3);
root.children[0]->children[0]->addChildren(2);
root.children[1]->addChildren(5);
root.children[2]->addChildren(5);
root.children[2]->children[1]->addChildren(2);
root.children[2]->children[1]->children[1]->addChildren(2);
cairo_surface_t *surface;
cairo_t *cr;
surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 600, 600);
cr = cairo_create(surface);
cairo_rectangle(cr, 0.0, 0.0, 600, 600);
cairo_set_source_rgb(cr, 1, 1, 1);
cairo_fill(cr);
cairo_set_line_width(cr, 2);
for (int i=0; i<6; i++) {
cairo_arc(cr, 300, 300, 40*i, 0, 2 * M_PI);
cairo_set_source_rgb(cr, .5, .5, .5);
cairo_stroke(cr);
}
draw(&root, cr);
cairo_surface_write_to_png(surface, "image.png");
cairo_destroy(cr);
cairo_surface_destroy(surface);
return 0;
}
Update 2:
Just to make it easier for you, here is how to center the nodes:
for (int i=0; i<root->children.size(); i++) {
float centerAdjust = 0;
if (root->parent != 0) {
centerAdjust = (-root->angleRange + root->angleRange / n) / 2;
}
root->children[i]->angle = root->angle + root->angleRange/n * i + centerAdjust;
root->children[i]->angleRange = root->angleRange/n;
Showing a more populated tree:
Here is an implementation of the algorithm from the article that should work (note: I didn't compile it since I don't have other parts of your program):
void Tree::CalculateAngles()
{
// IsEmpty() returns true if the tree is empty, false otherwise
if (!IsEmpty())
{
Node* pRoot = GetNodesInDepth(0).at(0);
pRoot->SetAngle(0);
// Relative to the current angle
pRoot->SetTangentLimit(PI);
// Absolute limit
pRoot->SetLowerBisector(-PI);
pRoot->SetHigherBisector(PI);
}
for (int depth = 1; depth < GetDepth() + 1; depth++)
{
double dDepth = (double)depth;
// The last non-leaf node in of the current depth (i.e. node with children)
Node* pPreviousNonleafNode = NULL;
// The first non-leaf node
Node* pFirstNonleafNode = NULL;
// The parent of the previous node
Node* pPreviousParent = NULL;
int indexInCurrentParent = 0;
double dTangentLimt = acos( dDepth / (dDepth + 1.0) );
for (int i = 0; i < GetNodesInDepth(depth).size(); i++)
{
Node* pCurrentNode = GetNodesInDepth(depth).at(i);
Node* pParent = pCurrentNode->GetParent();
if (pParent != pPreviousParent)
{
pPreviousParent = pParent;
indexInCurrentParent = 0;
}
// (GetMaxChildAngle() - GetMinChildAngle()) / GetChildCount()
double angleSpace = pParent->GetAngleSpace();
pCurrentNode->SetAngle(angleSpace * (indexInCurrentParent + 0.5));
pCurrentNode->SetTangentLimit(dTangentLimt);
if (pCurrentNode->IsParent())
{
if (!pPreviousNonleafNode)
{
pFirstNonleafNode = pCurrentNode;
}
else
{
double dBisector = (pPreviousNonleafNode->GetAngle() + pCurrentNode->GetAngle()) / 2.0;
pPreviousNonleafNode->SetHigherBisector(dBisector);
pCurrentNode->SetLowerBisector(dBisector);
}
pPreviousNonleafNode = pCurrentNode;
}
indexInCurrentParent++;
}
if (pPreviousNonleafNode && pFirstNonleafNode)
{
if (pPreviousNonleafNode == pFirstNonleafNode)
{
double dAngle = pFirstNonleafNode->GetAngle();
pFirstNonleafNode->SetLowerBisector(dAngle - PI);
pFirstNonleafNode->SetHigherBisector(dAngle + PI);
}
else
{
double dBisector = PI + (pPreviousNonleafNode->GetAngle() + pFirstNonleafNode->GetAngle()) / 2.0;
pFirstNonleafNode->SetLowerBisector(dBisector);
pPreviousNonleafNode->SetHigherBisector(dBisector);
}
}
}
}
void Tree::CalculatePositions()
{
for (int depth = 0; depth < GetDepth() + 1; depth++)
{
double redius = SPACING * depth;
for (int i = 0; i < GetNodesInDepth(depth).size(); i++)
{
Node* pCurrentNode = GetNodesInDepth(depth).at(i);
double angle = pCurrentNode->GetAngle();
pCurrentNode->SetXRadial(redius * qCos(angle) + MIDDLE(m_nWidth));
pCurrentNode->SetYRadial(redius * qSin(angle) + MIDDLE(m_nHeight));
}
}
}
void Tree::CalculateLayout ()
{
CalculateAngles();
CalculatePositions();
}
double Node::GetAngleSpace()
{
return (GetMaxChildAngle() - GetMinChildAngle()) / GetChildCount();
}
Note: I tried to mimic your code style so you won't have to refactor it to match other parts of your program.
P.S. If you spot any bugs, please notify me in the comments - I'll edit my answer.

Incorrect output on changing sequence of declarations

Implemention of Sutherland-Hodgeman polygon clipping. This order of declaration of these 2 statements gives correct output, reverse does not.
int numberOfVertices = 5;
Point pointList[] = { {50,50}, {200,300}, {310,110}, {130,90}, {70,40} };
The exact error which comes when the declarations are reversed is that the bottom clipper, produces an empty set of vertices so no polygon is displayed after clipping.
What is the reason for this error?
Code:
#include <iostream>
#include <GL/glut.h>
#define MAXVERTICES 10
#define LEFT 0
#define RIGHT 1
#define TOP 2
#define BOTTOM 3
using namespace std;
/* Clipping window */
struct Window {
double xmin;
double xmax;
double ymin;
double ymax;
};
struct Point {
double x;
double y;
};
/* If I interchange these two lines, the code doesn't work. */
/**************/
int numberOfVertices = 5;
Point pointList[] = { {50,50}, {200,300}, {310,110}, {130,90}, {70,40} };
/**************/
const Window w = { 100, 400, 60, 200 };
/* Checks whether a point is inside or outside a window side */
int isInside(Point p, int side) {
switch(side) {
case LEFT:
return p.x >= w.xmin;
case RIGHT:
return p.x <= w.xmax;
case TOP:
return p.y <= w.ymax;
case BOTTOM:
return p.y >= w.ymin;
}
}
/* Calculates intersection of a segment and a window side */
Point intersection(Point p1, Point p2, int side) {
Point temp;
double slope, intercept;
bool infinite;
/* Find slope and intercept of segment, taking care of inf slope */
if(p2.x - p1.x != 0) {
slope = (p2.y - p1.y) / (p2.x - p1.x);
infinite = false;
} else {
infinite = true;
}
intercept = p1.y - p1.x * slope;
/* Calculate intersections */
switch(side) {
case LEFT:
temp.x = w.xmin;
temp.y = temp.x * slope + intercept;
break;
case RIGHT:
temp.x = w.xmax;
temp.y = temp.x * slope + intercept;
break;
case TOP:
temp.y = w.ymax;
temp.x = infinite ? p1.x : (temp.y - intercept) / slope;
break;
case BOTTOM:
temp.y = w.ymin;
temp.x = infinite ? p1.x : (temp.y - intercept) / slope;
break;
}
return temp;
}
/* Clips polygon against a side, updating the point list
(called once for each side) */
void clipAgainstSide(int sideToClip) {
int i, j=0;
Point s,p;
Point outputList[MAXVERTICES];
/* Main algorithm */
s = pointList[numberOfVertices-1];
for(i=0 ; i<numberOfVertices ; i++) {
p = pointList[i];
if(isInside(p, sideToClip)) {
/* p inside */
if(!isInside(s, sideToClip)) {
/* p inside, s outside */
outputList[j] = intersection(p, s, sideToClip);
j++;
}
outputList[j] = p;
j++;
}
else if(isInside(s, sideToClip)) {
/* s inside, p outside */
outputList[j] = intersection(s, p, sideToClip);
j++;
}
s = p;
}
/* Updating number of points and point list */
numberOfVertices = j;
/* ERROR: In last call with BOTTOM argument, numberOfVertices becomes 0 */
/* all earlier 3 calls have correct output */
cout<<numberOfVertices<<endl;
for(i=0 ; i<numberOfVertices ; i++) {
pointList[i] = outputList[i];
}
}
void SutherlandHodgemanPolygonClip() {
clipAgainstSide(LEFT);
clipAgainstSide(RIGHT);
clipAgainstSide(TOP);
clipAgainstSide(BOTTOM);
}
void init() {
glClearColor(1,1,1,0);
glMatrixMode(GL_PROJECTION);
gluOrtho2D(0,1000,0,500);
}
void display() {
glClear(GL_COLOR_BUFFER_BIT);
/* Displaying ORIGINAL box and polygon */
glColor3f(0,0,1);
glBegin(GL_LINE_LOOP);
glVertex2i(w.xmin, w.ymin);
glVertex2i(w.xmin, w.ymax);
glVertex2i(w.xmax, w.ymax);
glVertex2i(w.xmax, w.ymin);
glEnd();
glColor3f(1,0,0);
glBegin(GL_LINE_LOOP);
for(int i=0 ; i<numberOfVertices ; i++) {
glVertex2i(pointList[i].x, pointList[i].y);
}
glEnd();
/* Clipping */
SutherlandHodgemanPolygonClip();
/* Displaying CLIPPED box and polygon, 500px right */
glColor3f(0,0,1);
glBegin(GL_LINE_LOOP);
glVertex2i(w.xmin+500, w.ymin);
glVertex2i(w.xmin+500, w.ymax);
glVertex2i(w.xmax+500, w.ymax);
glVertex2i(w.xmax+500, w.ymin);
glEnd();
glColor3f(1,0,0);
glBegin(GL_LINE_LOOP);
for(int i=0 ; i<numberOfVertices ; i++) {
glVertex2i(pointList[i].x+500, pointList[i].y);
}
glEnd();
glFlush();
}
int main(int argc, char** argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(1000,500);
glutCreateWindow("Sutherland-Hodgeman polygon clipping");
init();
glutDisplayFunc(display);
glutMainLoop();
return 0;
}
You have a memory stomping bug -- you're writing the pointList array with an invalid index, which overwrites the memory immediately afterwards. Your original code just happens to work, because the memory after it isn't used, but when you switch the order of declarations, the memory stomping overwrites the variable numberOfVertices.
I'd suggest running your program with Valgrind to find where the memory stomping is occurring.
In
if(isInside(p, sideToClip)) {
/* p inside */
if(!isInside(s, sideToClip)) {
/* p inside, s outside */
outputList[j] = intersection(p, s, sideToClip);
j++;
}
outputList[j] = p;
j++;
}
else if(isInside(s, sideToClip)) {
}
s = p;
}
/* Updating number of points and point list */
numberOfVertices = j;
for(i=0 ; i<numberOfVertices ; i++) {
pointList[i] = outputList[i];
}
You can increase numberOfVertices, but pointList has only space for the initial points. Declare it
Point pointList[MAXVERTICES] = { ... };
to have enough space.