Apologies for the wall of code below... but I'm not 100% sure of where the exact issue is. I'm using the Sutherland Hodgman clipping algorithm to find the contact points in my collision detection system (physics engine for my undergrad thesis). The vertices it returns are MOSTLY correct however I often get a lot of false positives on the InsideEdge function or incorrect intersections. If anyone can help I'd be so grateful! I have tried with many different input vertices and the result varies, however the X-axis does seem to be the most consistently correct.
Example IO with visual:
Input: clipping vertices [ (2.0, 2.0), (2.0, -2.0), (-2.0, -2.0), (-2.0, 2.0) ], poly vertices [ (2.5, 3.0), (2.5, 1.0), (0.5, 1.0), (0.5, 3.0) ]
Output: (2.0, 1.0), (0.5, 1.0), (0.5, 3.0 (wrong))
bool SAT::InsideEdge(double px, double py, double edgeMaxX, double edgeMaxY, double edgeMinX, double edgeMinY)
{
double one = (edgeMaxX - edgeMinX) * (py - edgeMinY);
double two = (edgeMaxY - edgeMinY) * (px - edgeMinX);
return (one - two) < 0;
}
void SAT::SutherlandHodgman(std::vector<Vector3>& _clipped, const Vector3& normal, const Vector3* polyVertices, const Vector3* clippingVertices)
{
const unsigned maxPoints = 16;
Vector3 newPoints[maxPoints];
for (unsigned i = 0; i < numVertices; i++)
{
newPoints[i] = polyVertices[i];
}
unsigned newSize = 0;
for (unsigned edge = 0; edge < numEdges; edge++) //for each clipping edge
{
//NOTE: axes is a 2D array to define which two axes to consider out of x, y, z
Vector3 edgeMin = clippingVertices[edge];
Vector3 edgeMax = clippingVertices[(edge + 1) % numEdges];
for (unsigned v = 0; v < numVertices; v++) //for each input vertex
{
Vector3 v1 = newPoints[v];
Vector3 v2 = newPoints[(v + 1) % numVertices];
bool insideEdge1 = InsideEdge(v1[axes[0]], v1[axes[1]], edgeMax[axes[0]], edgeMax[axes[1]], edgeMin[axes[0]], edgeMin[axes[1]]);
bool insideEdge2 = InsideEdge(v2[axes[0]], v2[axes[1]], edgeMax[axes[0]], edgeMax[axes[1]], edgeMin[axes[0]], edgeMin[axes[1]]);
if (insideEdge1 && insideEdge2)
{
newPoints[newSize] = v2;
newSize++;
}
else if (!insideEdge1 && insideEdge2)
{
newPoints[newSize] = CalculateIntersection(v1, v2, axes, edgeMin, edgeMax);
newSize++;
newPoints[newSize] = v2;
newSize++;
}
else if (insideEdge1 && !insideEdge2)
{
newPoints[newSize] = CalculateIntersection(v1, v2, axes, edgeMin, edgeMax);
newSize++;
}
}
numVertices = newSize;
if (numVertices >= maxPoints)
break;
}
for (unsigned i = 0; i < numVertices; i++)
{
//Removes duplicates before adding to the final list
VerifyVertex(_clipped, newPoints[i]);
}
}
And the calculate intersection code...
//x intersect
double num = (x1 * y2 - y1 * x2) * (x3 - x4) - (x1 - x2) * (x3 * y4 - y3 * x4);
double den = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4);
double X = num / den;
//y intersect
num = (x1 * y2 - y1 * x2) * (y3 - y4) - (y1 - y2) * (x3 * y4 - y3 * x4);
den = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4);
double Y = num / den;
Vector3 intersection;
intersection[axes[0]] = X;
intersection[axes[1]] = Y;
//Get the value of the remaining axis
double percAcrossLine = 1;
if (x2 != 0)
percAcrossLine = (x1 + X) / x2;
else if (y2 != 0)
percAcrossLine = (y1 + Y) / y2;
unsigned i = 0;
if (axes[0] == 0)
{
if (axes[1] == 1)
i = 2;
else if (axes[1] == 2)
i = 1;
}
intersection[i] = v1[i] + (v2[i] - v1[i]) * percAcrossLine;
return intersection;
Related
I'm trying to draw a cube using software rendering. So I have I'm drawing a cube out of triangles. So I render a solid triangle. The cube is rendered successfully, but there are flicker while rotating it.
here is my solid triangle filling, can somebody notice a problem in the algorithm?
void Rasterizer::DrawSolidTriangle(int x0, int y0, int x1, int y1, int x2, int y2, Color&color)
{
// Sort our points into order of y
// 0 top
// 2 middle
// 1 bottom
if (y1 < y0)
{
swap(y1, y0);
swap(x1, x0);
}
if (y2 < y0)
{
swap(y2, y0);
swap(x2, x0);
}
if (y1 < y2)
{
swap(y2, y1);
swap(x2, x1);
}
float xl_edge = (float)x0; // left edge
float xr_edge = (float)x0; // right edge
float dxldy;
float dxrdy;
float dxdy1 = (float)(x2 - x0) / (y2 - y0);
float dxdy2 = (float)(x1 - x0) / (y1 - y0);
if (dxdy1 < dxdy2)
{
dxldy = dxdy1;
dxrdy = dxdy2;
}
else
{
dxldy = dxdy2;
dxrdy = dxdy1;
}
// Top of the triangle
for (int y = y0; y<y2; y++)
{
for (int x = xl_edge; x<xr_edge; x++)
{
SetPixel((unsigned int)x, (unsigned int)y, color);
}//end for loop x
xl_edge = xl_edge + dxldy;
xr_edge = xr_edge + dxrdy;
}// end for loop y
// Bottom half of the triangle
if (dxdy1 < dxdy2)
{
dxldy = (float)(x2 - x1) / (y2 - y1);
}
else
{
dxrdy = (float)(x2 - x1) / (y2 - y1);
}
for (int y = y2; y<y1; y++)
{
for (int x = xl_edge; x<xr_edge; x++)
{
SetPixel((unsigned int)x, (unsigned int)y, color);
}//end for loop x
xl_edge = xl_edge + dxldy;
xr_edge = xr_edge + dxrdy;
}// end for loop y
}
here is a screenshot of the problem, when rotating the cube so slow it does appear here:
Im studying some code and I would like help with some math. Im trying to solve the equation of the tangent line on a circle with given point of tangency.
//(x1 - p)(x - p) +(y1 - q)(y - q) = r^2 I understand this formula
//variables
//x1 = point.x
//y1 = point.y
//p = center.x
//q = center.y
//r = radius
edit: here is the whole function, maybe it will help. My teacher gave it to me to study, but maybe he is trolling me :D
const std::pair<double, double> Arc::tangentEquation(const glm::vec3& center, const glm::vec3& pointA, float radius) const {
if (radius <= 0.0f)
throw std::domain_error("Radius can't be negative or 0");
// Jednadžba tangente u točki T
// (x1 - p)(x - p) + (y1 - q)(y - q) = r^2
glm::vec3 point = pointA + center;
double px = -1 * (center.x * point.x);
double qy = -1 * (center.y * point.y);
double x = point.x - center.x;
double y = point.y - center.y;
double k = 0.0;
double l = (pow(radius, 2) - (px + pow(center.x, 2) + qy + pow(center.y, 2)));
if (y == 0) { // paralelan s x os
k = l / x;
l = 0;
} else if (x == 0) { // paralelan s y os
l = l / y;
k = 0;
} else {
k = -x / y;
l = l / y;
}
return std::pair<double, double>(k, l);
}
The code does not implement the formula on the first line, so I don't think it is strange that you don't understand :-)
(x1 - p)(x - p) + (y1 - q)(y - q)
If we write out all the terms in the parenthesis multiplication, we get:
x1*x - p*x - p*x1 + p^2 + y1*y - q*y - q*y1 + q^2
(https://www.youtube.com/watch?v=3s_lroR5_1U for very pedagogic explanation)
But your code looses half of these terms....?
I have a std::vector with 3 points (2D) with values x >= 0 and x <= 512.
With these 3 points I have to calculate a draw that passes all of these 3 points.
Here
you see the 3 Points and the corresponding circle. I need a function to interpolate the points based on a variable which defines the accuracy (eg the number of points inbetween).
If its not clear: I work in C++.
To solve your issue you need to calculate center of triangle's circumscribed circle and it radius. Then find min X and max X from triangle coordinates then calculate delta between maxX - minX and divide delta to numbers of input points. Then in loop you iterates from minX to maxX and calculate coordinates by using circle formula R^2 = (x - centerX)^2 + (y - centerY)^2.
Below a small example
#include <iostream>
#include <vector>
#include <math.h>
template <typename T>
class CPoint2D
{
public:
CPoint2D(T _x, T _y)
: x(_x)
, y(_y)
{}
~CPoint2D()
{}
const T& X() const { return x; }
const T& Y() const { return y; }
private:
T x;
T y;
};
typedef CPoint2D<float> CPoint2Df;
bool GetCenterCircumscribedCircle(float x0, float y0,
float x1, float y1,
float x2, float y2,
float& centerX, float& centerY, float& radius)
{
if ((x0 == x1 && x1 == x2) ||
(y0 == y1 && y1 == y2))
{
return false;
}
float D = 2.0f * (y0 * x2 + y1 * x0 - y1 * x2 - y0 * x1 - y2 * x0 + y2 * x1);
centerX = ( y1 * x0 * x0
- y2 * x0 * x0
- y1 * y1 * y0
+ y2 * y2 * y0
+ x1 * x1 * y2
+ y0 * y0 * y1
+ x2 * x2 * y0
- y2 * y2 * y1
- x2 * x2 * y1
- x1 * x1 * y0
+ y1 * y1 * y2
- y0 * y0 * y2) / D;
centerY = ( x0 * x0 * x2
+ y0 * y0 * x2
+ x1 * x1 * x0
- x1 * x1 * x2
+ y1 * y1 * x0
- y1 * y1 * x2
- x0 * x0 * x1
- y0 * y0 * x1
- x2 * x2 * x0
+ x2 * x2 * x1
- y2 * y2 * x0
+ y2 * y2 * x1) / D;
radius = sqrt((x0 - centerX) * (x0 - centerX) + (y0 - centerY) * (y0 - centerY));
return true;
}
void CalculatePointsOnCirle(const std::vector<CPoint2Df>& triVertexes, std::vector<CPoint2Df>& outPoints, float stride)
{
if (triVertexes.size() != 3)
{
return;
}
const CPoint2Df& v1 = triVertexes[0];
const CPoint2Df& v2 = triVertexes[1];
const CPoint2Df& v3 = triVertexes[2];
float minX = std::min(v1.X(), v2.X());
minX = std::min(minX, v3.X());
float maxX = std::max(v1.X(), v2.X());
maxX = std::max(maxX, v3.X());
float deltaX = (maxX - minX) / stride;
float centerX;
float centerY;
float radius;
if (GetCenterCircumscribedCircle(v1.X(), v1.Y(),
v2.X(), v2.Y(),
v3.X(), v3.Y(),
centerX, centerY, radius))
{
for (float x = minX; x < maxX; x += deltaX)
{
float y = sqrt(radius * radius - (x - centerX) * (x - centerX));
outPoints.push_back(CPoint2Df(x, y));
}
}
}
int main(int argc, const char * argv[])
{
std::vector<CPoint2Df> triVertex = {CPoint2Df(0.0f, 0.0f),
CPoint2Df(256.0f, 256.0f),
CPoint2Df(512.0f, 0.0f)};
std::vector<CPoint2Df> outPoints;
CalculatePointsOnCirle(triVertex, outPoints, 4);
for (unsigned int i = 0; i < outPoints.size(); ++i)
{
printf("p[%d]: (%f, %f)\n", i, outPoints[i].X(), outPoints[i].Y());
}
return 0;
}
I'm trying to implement the Delaunay triangulation in C++. Currently it's working, but I'm not getting the correct amount of triangles.
I try it with 4 points in a square pattern : (0,0), (1,0), (0,1), (1,1).
Here's the algorithm I use :
std::vector<Triangle> Delaunay::triangulate(std::vector<Vec2f> &vertices) {
// Determinate the super triangle
float minX = vertices[0].getX();
float minY = vertices[0].getY();
float maxX = minX;
float maxY = minY;
for(std::size_t i = 0; i < vertices.size(); ++i) {
if (vertices[i].getX() < minX) minX = vertices[i].getX();
if (vertices[i].getY() < minY) minY = vertices[i].getY();
if (vertices[i].getX() > maxX) maxX = vertices[i].getX();
if (vertices[i].getY() > maxY) maxY = vertices[i].getY();
}
float dx = maxX - minX;
float dy = maxY - minY;
float deltaMax = std::max(dx, dy);
float midx = (minX + maxX) / 2.f;
float midy = (minY + maxY) / 2.f;
Vec2f p1(midx - 20 * deltaMax, midy - deltaMax);
Vec2f p2(midx, midy + 20 * deltaMax);
Vec2f p3(midx + 20 * deltaMax, midy - deltaMax);
// Add the super triangle vertices to the end of the vertex list
vertices.push_back(p1);
vertices.push_back(p2);
vertices.push_back(p3);
// Add the super triangle to the triangle list
std::vector<Triangle> triangleList = {Triangle(p1, p2, p3)};
// For each point in the vertex list
for(auto point = begin(vertices); point != end(vertices); point++)
{
// Initialize the edges buffer
std::vector<Edge> edgesBuff;
// For each triangles currently in the triangle list
for(auto triangle = begin(triangleList); triangle != end(triangleList);)
{
if(triangle->inCircumCircle(*point))
{
Edge tmp[3] = {triangle->getE1(), triangle->getE2(), triangle->getE3()};
edgesBuff.insert(end(edgesBuff), tmp, tmp + 3);
triangle = triangleList.erase(triangle);
}
else
{
triangle++;
}
}
// Delete all doubly specified edges from the edge buffer
// Black magic by https://github.com/MechaRage
auto ite = begin(edgesBuff), last = end(edgesBuff);
while(ite != last) {
// Search for at least one duplicate of the current element
auto twin = std::find(ite + 1, last, *ite);
if(twin != last)
// If one is found, push them all to the end.
last = std::partition(ite, last, [&ite](auto const &o){ return !(o == *ite); });
else
++ite;
}
// Remove all the duplicates, which have been shoved past "last".
edgesBuff.erase(last, end(edgesBuff));
// Add the triangle to the list
for(auto edge = begin(edgesBuff); edge != end(edgesBuff); edge++)
triangleList.push_back(Triangle(edge->getP1(), edge->getP2(), *point));
}
// Remove any triangles from the triangle list that use the supertriangle vertices
triangleList.erase(std::remove_if(begin(triangleList), end(triangleList), [p1, p2, p3](auto t){
return t.containsVertex(p1) || t.containsVertex(p2) || t.containsVertex(p3);
}), end(triangleList));
return triangleList;
}
And here's what I obtain :
Triangle:
Point x: 1 y: 0
Point x: 0 y: 0
Point x: 1 y: 1
Triangle:
Point x: 1 y: 0
Point x: 1 y: 1
Point x: 0 y: 1
Triangle:
Point x: 0 y: 0
Point x: 1 y: 1
Point x: 0 y: 1
While this would be the correct output :
Triangle:
Point x: 1 y: 0
Point x: 0 y: 0
Point x: 0 y: 1
Triangle:
Point x: 1 y: 0
Point x: 1 y: 1
Point x: 0 y: 1
I have no idea why there is a triangle with the (0, 0) and the (1, 1).
I need an outside eye to review the code and find out what's going wrong.
All the sources are on my Github repo. Feel free to fork it and to PR your code.
Thanks!
what about this implementation of Paul Bourke's Delaunay triangulation algorithm. Take a look at Triangulate() I have used this source many times without any complains
#include <iostream>
#include <stdlib.h> // for C qsort
#include <cmath>
#include <time.h> // for random
const int MaxVertices = 500;
const int MaxTriangles = 1000;
//const int n_MaxPoints = 10; // for the test programm
const double EPSILON = 0.000001;
struct ITRIANGLE{
int p1, p2, p3;
};
struct IEDGE{
int p1, p2;
};
struct XYZ{
double x, y, z;
};
int XYZCompare(const void *v1, const void *v2);
int Triangulate(int nv, XYZ pxyz[], ITRIANGLE v[], int &ntri);
int CircumCircle(double, double, double, double, double, double, double, double, double&, double&, double&);
using namespace std;
////////////////////////////////////////////////////////////////////////
// CircumCircle() :
// Return true if a point (xp,yp) is inside the circumcircle made up
// of the points (x1,y1), (x2,y2), (x3,y3)
// The circumcircle centre is returned in (xc,yc) and the radius r
// Note : A point on the edge is inside the circumcircle
////////////////////////////////////////////////////////////////////////
int CircumCircle(double xp, double yp, double x1, double y1, double x2,
double y2, double x3, double y3, double &xc, double &yc, double &r){
double m1, m2, mx1, mx2, my1, my2;
double dx, dy, rsqr, drsqr;
/* Check for coincident points */
if(abs(y1 - y2) < EPSILON && abs(y2 - y3) < EPSILON)
return(false);
if(abs(y2-y1) < EPSILON){
m2 = - (x3 - x2) / (y3 - y2);
mx2 = (x2 + x3) / 2.0;
my2 = (y2 + y3) / 2.0;
xc = (x2 + x1) / 2.0;
yc = m2 * (xc - mx2) + my2;
}else if(abs(y3 - y2) < EPSILON){
m1 = - (x2 - x1) / (y2 - y1);
mx1 = (x1 + x2) / 2.0;
my1 = (y1 + y2) / 2.0;
xc = (x3 + x2) / 2.0;
yc = m1 * (xc - mx1) + my1;
}else{
m1 = - (x2 - x1) / (y2 - y1);
m2 = - (x3 - x2) / (y3 - y2);
mx1 = (x1 + x2) / 2.0;
mx2 = (x2 + x3) / 2.0;
my1 = (y1 + y2) / 2.0;
my2 = (y2 + y3) / 2.0;
xc = (m1 * mx1 - m2 * mx2 + my2 - my1) / (m1 - m2);
yc = m1 * (xc - mx1) + my1;
}
dx = x2 - xc;
dy = y2 - yc;
rsqr = dx * dx + dy * dy;
r = sqrt(rsqr);
dx = xp - xc;
dy = yp - yc;
drsqr = dx * dx + dy * dy;
return((drsqr <= rsqr) ? true : false);
}
///////////////////////////////////////////////////////////////////////////////
// Triangulate() :
// Triangulation subroutine
// Takes as input NV vertices in array pxyz
// Returned is a list of ntri triangular faces in the array v
// These triangles are arranged in a consistent clockwise order.
// The triangle array 'v' should be malloced to 3 * nv
// The vertex array pxyz must be big enough to hold 3 more points
// The vertex array must be sorted in increasing x values say
//
// qsort(p,nv,sizeof(XYZ),XYZCompare);
///////////////////////////////////////////////////////////////////////////////
int Triangulate(int nv, XYZ pxyz[], ITRIANGLE v[], int &ntri){
int *complete = NULL;
IEDGE *edges = NULL;
IEDGE *p_EdgeTemp;
int nedge = 0;
int trimax, emax = 200;
int status = 0;
int inside;
int i, j, k;
double xp, yp, x1, y1, x2, y2, x3, y3, xc, yc, r;
double xmin, xmax, ymin, ymax, xmid, ymid;
double dx, dy, dmax;
/* Allocate memory for the completeness list, flag for each triangle */
trimax = 4 * nv;
complete = new int[trimax];
/* Allocate memory for the edge list */
edges = new IEDGE[emax];
/*
Find the maximum and minimum vertex bounds.
This is to allow calculation of the bounding triangle
*/
xmin = pxyz[0].x;
ymin = pxyz[0].y;
xmax = xmin;
ymax = ymin;
for(i = 1; i < nv; i++){
if (pxyz[i].x < xmin) xmin = pxyz[i].x;
if (pxyz[i].x > xmax) xmax = pxyz[i].x;
if (pxyz[i].y < ymin) ymin = pxyz[i].y;
if (pxyz[i].y > ymax) ymax = pxyz[i].y;
}
dx = xmax - xmin;
dy = ymax - ymin;
dmax = (dx > dy) ? dx : dy;
xmid = (xmax + xmin) / 2.0;
ymid = (ymax + ymin) / 2.0;
/*
Set up the supertriangle
his is a triangle which encompasses all the sample points.
The supertriangle coordinates are added to the end of the
vertex list. The supertriangle is the first triangle in
the triangle list.
*/
pxyz[nv+0].x = xmid - 20 * dmax;
pxyz[nv+0].y = ymid - dmax;
pxyz[nv+1].x = xmid;
pxyz[nv+1].y = ymid + 20 * dmax;
pxyz[nv+2].x = xmid + 20 * dmax;
pxyz[nv+2].y = ymid - dmax;
v[0].p1 = nv;
v[0].p2 = nv+1;
v[0].p3 = nv+2;
complete[0] = false;
ntri = 1;
/*
Include each point one at a time into the existing mesh
*/
for(i = 0; i < nv; i++){
xp = pxyz[i].x;
yp = pxyz[i].y;
nedge = 0;
/*
Set up the edge buffer.
If the point (xp,yp) lies inside the circumcircle then the
three edges of that triangle are added to the edge buffer
and that triangle is removed.
*/
for(j = 0; j < ntri; j++){
if(complete[j])
continue;
x1 = pxyz[v[j].p1].x;
y1 = pxyz[v[j].p1].y;
x2 = pxyz[v[j].p2].x;
y2 = pxyz[v[j].p2].y;
x3 = pxyz[v[j].p3].x;
y3 = pxyz[v[j].p3].y;
inside = CircumCircle(xp, yp, x1, y1, x2, y2, x3, y3, xc, yc, r);
if (xc + r < xp)
// Suggested
// if (xc + r + EPSILON < xp)
complete[j] = true;
if(inside){
/* Check that we haven't exceeded the edge list size */
if(nedge + 3 >= emax){
emax += 100;
p_EdgeTemp = new IEDGE[emax];
for (int i = 0; i < nedge; i++) { // Fix by John Bowman
p_EdgeTemp[i] = edges[i];
}
delete []edges;
edges = p_EdgeTemp;
}
edges[nedge+0].p1 = v[j].p1;
edges[nedge+0].p2 = v[j].p2;
edges[nedge+1].p1 = v[j].p2;
edges[nedge+1].p2 = v[j].p3;
edges[nedge+2].p1 = v[j].p3;
edges[nedge+2].p2 = v[j].p1;
nedge += 3;
v[j] = v[ntri-1];
complete[j] = complete[ntri-1];
ntri--;
j--;
}
}
/*
Tag multiple edges
Note: if all triangles are specified anticlockwise then all
interior edges are opposite pointing in direction.
*/
for(j = 0; j < nedge - 1; j++){
for(k = j + 1; k < nedge; k++){
if((edges[j].p1 == edges[k].p2) && (edges[j].p2 == edges[k].p1)){
edges[j].p1 = -1;
edges[j].p2 = -1;
edges[k].p1 = -1;
edges[k].p2 = -1;
}
/* Shouldn't need the following, see note above */
if((edges[j].p1 == edges[k].p1) && (edges[j].p2 == edges[k].p2)){
edges[j].p1 = -1;
edges[j].p2 = -1;
edges[k].p1 = -1;
edges[k].p2 = -1;
}
}
}
/*
Form new triangles for the current point
Skipping over any tagged edges.
All edges are arranged in clockwise order.
*/
for(j = 0; j < nedge; j++) {
if(edges[j].p1 < 0 || edges[j].p2 < 0)
continue;
v[ntri].p1 = edges[j].p1;
v[ntri].p2 = edges[j].p2;
v[ntri].p3 = i;
complete[ntri] = false;
ntri++;
}
}
/*
Remove triangles with supertriangle vertices
These are triangles which have a vertex number greater than nv
*/
for(i = 0; i < ntri; i++) {
if(v[i].p1 >= nv || v[i].p2 >= nv || v[i].p3 >= nv) {
v[i] = v[ntri-1];
ntri--;
i--;
}
}
delete[] edges;
delete[] complete;
return 0;
}
int XYZCompare(const void *v1, const void *v2){
XYZ *p1, *p2;
p1 = (XYZ*)v1;
p2 = (XYZ*)v2;
if(p1->x < p2->x)
return(-1);
else if(p1->x > p2->x)
return(1);
else
return(0);
}
I didn't go with a debugger, but from the resulting triangles it seems that this is an accuracy/ambiguity problem.
When you are triangulating a square there are two ways to split it into triangles and both are OK from Delaunay criteria (circumscribed circle center is on border of triangle).
So if you evaluate every triangle independently you may sometimes get even 4 triangles (depending on implementation).
Normally in such cases I recommend to build algorithm as a series of questions which cannot produce contradicting answers. In this case the question is "to which point goes triangle based on edge (1,0)-(1,1)". But often this requires significant changes to the algorithm.
A quick fix usually involves adding some tolerances for comparisons and extra checks (like non-intersecting triangles). But usually it just makes problems rarer.
Most likely you didn't delete all the double edges, especially not the edges from same triangles but with vertices only in another order. The correct function is in the answer from #cMinor.
What i want is that, I have info of 2 points, the starting x,y and mid point x,y and i need to find end line like until some kind of border, like window
here is what I do:
//function for calculating the end point from one location, to specific end location
//like a bullet moving forward in a line
//x,y start location(mouse), x2,y2(rect point location one of the 4) mid point, qx,qy end point(shadow or triangle draw location)
void screenEnd(int x, int y, int x2, int y2, int*qx,int*qy)
{
x = x2-x;
y = y2-y;
float tx = x2,ty = y2;
float result = atan2((float)y,(float)x) * 180 / PI;
float tempx = cos ( result * PI / 180.0 );
float tempy = sin ( result * PI / 180.0 );
bool check = true;
//this part needs optimization
while(check)
{
if(tx < 0|| ty < 0|| tx > 1280 || ty > 720)
{
check = false;
}
else
{
tx += tempx;
ty += tempy;
}
}
*qx = tx;
*qy = ty;
}
what I do is just increase point until it reaches the end.
Is there any way faster?
A classic window clipping task.
Consider a parametric equation where p is the point (x,y).
p(0) = x, y
p(0.5) = x2, y2
p(1) = x+2*(x2-x), y + 2*(y2-y)
p(t) = p(0) + t*(p(1) - p(0))
clip window = 0,0 to 720, 1280 (suspect you really want 719,1279)
The segment to draw initially ranges from t=0.0 to t=1.0. The segment is tested against each of the 4 sides of the bounding box, potentially reducing the t range. Maybe even eliminating all together.
Follows is some old code, enough to get you going.
#include <math.h>
int cliptest(int dz, int z, double *t0, double *t1) {
if (dz < 0) {
double t = ((double) z) / dz;
if (t > *t1)
return 0;
if (t > *t0)
*t0 = t;
} else if (dz > 0) {
double t = ((double) z) / dz;
if (t < *t0)
return 0;
if (t < *t1)
*t1 = t;
} else {
if (z < 0)
return 0;
}
return 1;
}
int clipper(int *px0, int *py0, int *px1, int *py1, int minx, int miny,
int maxx, int maxy) {
double t0, t1;
int dx, dy;
t0 = 0.0;
t1 = 1.0;
dy = *py1 - *py0;
dx = *px1 - *px0;
if (cliptest(-dx, *px0 - minx, &t0, &t1)
&& cliptest(dx, maxx - *px0, &t0, &t1)
&& cliptest(-dy, *py0 - miny, &t0, &t1)
&& cliptest(dy, maxy - *py0, &t0, &t1)) {
if (t1 < 1.0) {
*px1 = round(*px0 + t1*dx);
*py1 = round(*py0 + t1*dy);
}
if (t0 > 0.0) {
*px0 = round(*px0 + t0*dx);
*py0 = round(*py0 + t0*dy);
}
return 1;
}
return 0;
}
int x0 = x;
int y0 = y;
int x1 = x + 2*(x2-x); // Form end point
int y1 = x + 2*(y2-y);
if (clipper(&x0, &y0, &x1, &y1, 0, 0, 720, 1280))
Draw(x0, y0, x1, y2);
else
Handle_LineTotallyClippedOut();