Help me please with how to find Centroid of Quadrilateral? I have this constructor:
public Quadrilateral(Point a, Point b, Point c, Point d) {
if (a == null || b == null || c == null || d == null) {
throw new IllegalArgumentException();
}
if (collinear(a, b, c)) {
throw new IllegalArgumentException();
}
double[][] points = { { a.getX(), a.getY() }, { b.getX(), b.getY() },
{ c.getX(), c.getY() }, { d.getX(), d.getY() } };
if (!isConvex(points)) {
throw new IllegalArgumentException();
}
this.a = a;
this.b = b;
this.c = c;
this.d = d;
}
Then I find four centroids of triangles inside quadrilateral:
public Point centroid() {
Point center1 = centroidTriangle(a,b,c);
Point center2 = centroidTriangle(a,c,d);
Point center3 = centroidTriangle(a,d,b);
Point center4 = centroidTriangle(b,d,c);
return null;
}
private Point centroidTriangle(Point a, Point b, Point c) {
double xx = (a.getX() + b.getX() + c.getX()) / 3;
double xy = (a.getY() + b.getY() + c.getY()) / 3;
return new Point(xx, xy);
}
Then I need to find two diagonals between "leftUp" - "rightDown" and "leftDown"-"rightUp" centroids.
But how can I find position of centroid to make correct pairs of them? And how to find then centroid of all quadrilateral?
Good day.
After finding centers of triangles you need to find intersection of lines which made with (center1,center2) and (center3,center4). So point of intersection is Centroid of Quadrilateral
public Point centroid() {
Point center1 = centroidTriangle(a,b,c);
Point center2 = centroidTriangle(a,c,d);
Point center3 = centroidTriangle(a,d,b);
Point center4 = centroidTriangle(b,d,c);
return new Segment(center1,center2)
.intersection(new Segment(center3,center4));
}
Segment:
import java.util.Objects;
import static java.lang.Math.sqrt;
import static java.lang.StrictMath.pow;
class Segment {
Point start;
Point end;
public Segment(Point start, Point end) {
if(Objects.isNull(start) || Objects.isNull(end) || start.equals(end))
throw new RuntimeException();
this.start = start;
this.end = end;
}
double length() {
return sqrt(pow(end.getX() - start.getX(), 2) + pow(end.getY() - start.getY(), 2));
}
Point middle() {
return new Point((start.getX() + end.getX()) / 2, (start.getY() + end.getY()) / 2);
}
Point intersection(Segment another) {
double k1 = (end.getY() - start.getY()) / (end.getX() - start.getX());
double k2 = (another.end.getY() - another.start.getY()) / (another.end.getX() - another.start.getX());
if (k1 == k2) return null;
double b1 = (start.getY() * end.getX() - end.getY() * start.getX()) / (end.getX() - start.getX());
double b2 = (another.start.getY() * another.end.getX() - another.end.getY() * another.start.getX()) /
(another.end.getX() - another.start.getX());
double x = (b2 - b1) / (k1 - k2);
double y = (k1 * b2 - k2 * b1) / (k1 - k2);
if ((x > start.getX() && x > end.getX()) || (x > another.start.getX() && x > another.end.getX()) ||
(x < start.getX() && x < end.getX()) || (x < another.start.getX() && x < another.end.getX()) ||
(y > start.getY() && y > end.getY()) || (y > another.start.getY() && y > another.end.getY()) ||
(y < start.getY() && y < end.getY()) || (y < another.start.getY() && y < another.end.getY()))
return null;
return new Point(x, y);
}
}
Related
Following piece of java code is a solution to determine whether a 2D Point is within a Polygon or not (taken from here). I think this code has some problems. For example for this polygon:
Point[] polygon = new Point[5];
polygon[0] = new Point(30,20);
polygon[1] = new Point(80,10);
polygon[2] = new Point(75,100);
polygon[3] = new Point(40,100);
polygon[4] = new Point(55,65);
It returns true (inside) for (76,82) but this point is on the edge (Code returns false correctly for another point on the edge : (45,17)).
Also it returns false (not inside) for (45,90) but it is inside of the polygon. What is the problem?
public boolean IsPointInPolygon(Point p, Point[] polygon)
{
double minX = polygon[0].x;
double maxX = polygon[0].x;
double minY = polygon[0].y;
double maxY = polygon[0].y;
for ( int i = 1 ; i < polygon.length; i++ )
{
Point q = polygon[i];
minX = Math.min(q.x, minX);
maxX = Math.max(q.x, maxX);
minY = Math.min(q.y, minY);
maxY = Math.max(q.y, maxY);
}
if ( p.x <= minX || p.x >= maxX || p.y <= minY || p.y >= maxY )
{
return false;
}
boolean inside = false;
int j = polygon.length - 1;
for (int i = 0 ;i < polygon.length ; j = i++)
{
if (( polygon[i].y > p.y ) != ( polygon[j].y > p.y) &&
p.x <= (polygon[j].x - polygon[i].x ) * ( p.y - polygon[i].y ) / ( polygon[j].y - polygon[i].y ) + polygon[i].x)
{
inside = !inside;
}
}
return inside;
}
I think I should change my code to below, but I am not sure !
float tempX = ((float)((polygon[i].x - polygon[j].x) * (p.y - polygon[i].y)) / (polygon[i].y - polygon[j].y)) + polygon[i].x;
if (p.x < tempX) {
inside = !inside;
}
else if (p.x == tempX) {
return false;
}
This algorithm
if ( p.x <= minX || p.x >= maxX || p.y <= minY || p.y >= maxY )
{
return false;
}
Is wrong. It only checks if the point is within a rectangle, bounded by minX, maxX, minY, maxY
You can't test if a point is within a polygon without using all the polygon vertices.
Use java.awt.Polygon :
public boolean isPointInPolygon(Point p, Point[] points)
{
Polygon polygon = new Polygon();//java.awt.Polygon
for(Point point : points) {
polygon.addPoint(point.x, point.y);
}
return polygon.contains(p);
}
Testing it with
Point[] points = new Point[5];
points[0] = new Point(30,20);
points[1] = new Point(80,10);
points[2] = new Point(75,100);
points[3] = new Point(40,100);
points[4] = new Point(55,65);
System.out.println(isPointInPolygon(new Point(76,82), points) );
prints out false.
I'm making a small sprouts app where the user can draw paths between dots or on the screen with paths. I create arraylists of the coordinates of the paths and then attempt to compare them four points at a time to see if they intersect with paths already drawn. Right now, it isn't detecting any collisions. Here some of my code so far:
//ArrayList of the currentPath that is being drawn
ArrayList<float[]> currentPath = new ArrayList<>();
//ArrayList of Paths that have been drawn so far
private ArrayList <ArrayList<float[]>> paths = new ArrayList<>();
public boolean checkPath() {
if (paths.size() == 0) {
return true;
} else {
boolean noCollisions = true;
for (int i = 0; i < paths.size(); i++) { //Loop through path array to compare each path
for (int j = 0; j < paths.get(i).size() - 1; j++) { //Loop through each path to compare points
for (int k = 0; k < currentPath.size() - 1; k++) {
float end1Y = currentPath.get(k + 1)[1];
float start1Y = currentPath.get(k)[1];
float start1X = currentPath.get(k)[0];
float end1X = currentPath.get(k + 1)[0];
float end2Y = paths.get(i).get(j + 1)[1];
float start2Y = paths.get(i).get(j)[1];
float start2X = paths.get(i).get(j)[0];
float end2X = paths.get(i).get(j + 1)[0];
double A1 = end1Y - start1Y;
double B1 = start1X - end1X;
double C1 = A1 * start1X + B1 + start1Y;
double A2 = end2Y - start2Y;
double B2 = start2X - end2X;
double C2 = A2 * start2X + B2 * start2Y;
double det = (A1 * B2) - (A2 * B1);
if (det == 0) {
//Lines are either parallel, are collinear or overlapping partially
if ((A1 * start2X) + (B1 * start2Y) == C1) {
//they are the on the same line, check if they are in the same space
if ((Math.min(start1X, end1X) < start2X) && (Math.max(start1X, end1X) > start2X)) {
noCollisions = false;
}
//one end point is okay, now checking the other
if ((Math.min(start1X, end1X) < end2X) && (Math.max(start1X, end1X) > end2X)) {
noCollisions = false;
} else{
noCollisions = true;
}
}
} else {
//Lines intersect somewhere, but do the segments intersect?
double x = (B2 * C1 - B1 * C2) / det;
double y = (A1 * C2 - A2 * C1) / det;
//check to see if the intersection is within the bounding box of the segments.
if((x > Math.min(start1X, end1X) && x < Math.max(start1X, end1X)) && (y > Math.min(start1Y, end1Y) && y < Math.max(start1Y, end1Y))){
//We are within the bounding box of the first line segment, now check the second
if((x > Math.min(start2X, end2X) && x < Math.max(start2X, end2X)) && (y > Math.min(start2Y, end2Y) && y < Math.max(start2Y, end2Y))){
//the segments intersect
noCollisions = false;
}
} else {
noCollisions = true;
}
}
}
}
}
return noCollisions;
}
}
I'm trying to use matrices and determinantes to figure out if there is any intersection occurring.
Please try to replace below line
double C1 = A1 * start1X + B1 + start1Y;
by following line
double C1 = A1 * start1X + B1 * start1Y;
Ain't this easier?
Region region1, region2;
boolean intersect;
Region clip = new Region(0, 0, screenWidth, screenHeight);
region1.setPath(path1, clip);
region2.setPath(path2, clip);
if (!region1.quickReject(region2))
intersect = true;
else intersect = false;
(I know I'm late)
I have created a function to calculate the intersection point of two line segment .
Unfortunantly the code below dosen't work if one of the segment is verticale
public static Point intersection(Segment s1, Segment s2) {
double x1 = s1.getP1().getX();
double y1 = s1.getP1().getY() ;
double x2 = s1.getP2().getX();
double y2 = s1.getP2().getY() ;
double x3 = s2.getP1().getX();
double y3 = s2.getP1().getY();
double x4 = s2.getP2().getX();
double y4 = s2.getP2().getY();
double d = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4);
if (d == 0) {
return null;
}
double xi = ((x3 - x4) * (x1 * y2 - y1 * x2) - (x1 - x2) * (x3 * y4 - y3 * x4)) / d;
double yi = ((y3 - y4) * (x1 * y2 - y1 * x2) - (y1 - y2) * (x3 * y4 - y3 * x4)) / d;
Point p = new Point(xi, yi);
if (xi < Math.min(x1, x2) || xi > Math.max(x1, x2)) {
return null;
}
if (xi < Math.min(x3, x4) || xi > Math.max(x3, x4)) {
return null;
}
return p;
}
the problem when i have a vertical line segment , this formula
double d = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4);
is equal to 0 and the method return null.
How can I handle this exception.
Thank you
Line intersection without special cases
Coming from a background of projective geometry, I'd write the points in homogeneous coordinates:
v1 = [x1, y1, 1]
v2 = [x2, y2, 1]
v3 = [x3, y3, 1]
v4 = [x4, y4, 1]
Then both the line joining two points and the intersection of two lines can be expressed using the cross product:
[x5, y5, z5] = (v1 × v2) × (v3 × v4)
which you can dehomogenize to find the resulting point as
[x5/z5, y5/z5]
without having to deal with any special cases. If your lines are parallel, the last point would lead to a division by zero, though, so you might want to catch that case.
Restriction to segments
The above is for infinite lines, though. You might want to keep the code which returns null if the point of intersection falls outside the bounding box. But if you want real segments, that code is incorrect: you could have a point of intersection which lies outside one of the segments but still inside the bounding box.
A proper check can be implemented using an orientation-checking predicate. The determinant of three of the vectors vi given above will have positive sign if the triangle they form has one orientation, and negative sign for the opposite orientation. So the points v3 and v4 lie on different sides of s1 if
det(v1, v2, v3) * det(v1, v2, v4) < 0
and in a similar way v1 and v2 lie on different sides of s2 if
det(v3, v4, v1) * det(v3, v4, v2) < 0
so if both of these are satisfied, you have an intersection between the segments. If you want to include the segment endpoints, change the < to a ≤ in these inequalities.
I have tried code it without testing... I hope it works! ^^
public static Point intersection(Segment s1, Segment s2) {
// Components of the first segment's rect.
Point v1 = new Point(s1.p2.x - s1.p1.x, s1.p2.y - s1.p1.y); // Directional vector
double a1 = v.y;
double b1 = -v.x;
double c1 = v1.x * s1.p1.y - s1.v.y * s1.p1.x;
// Components of the second segment's rect.
Point v2 = new Point(s2.p2.x - s2.p1.x, s2.p2.y - s2.p1.y);
double a2 = v2.y;
double b2 = -v2.x;
double c2 = v2.x * s2.p1.y - s2.v.y * s2.p1.x;
// Calc intersection between RECTS.
Point intersection = null;
double det = a1 * b2 - b1 * a2;
if (det != 0) {
intersection = new Point(
(b2 * (-c1) - b1 * (-c2)) / det;
(a1 * (-c2) - a2 * (-c1)) / det;
);
}
// Checks ff segments collides.
if (
intersection != null &&
(
(s1.p1.x <= intersection.x && intersection.x <= s1.p2.x) ||
(s1.p2.x <= intersection.x && intersection.x <= s1.p1.x)
) &&
(
(s1.p1.y <= intersection.y && intersection.y <= s1.p2.y) ||
(s1.p2.y <= intersection.y && intersection.y <= s1.p1.y)
) &&
(
(s2.p1.x <= intersection.x && intersection.x <= s2.p2.x) ||
(s2.p2.x <= intersection.x && intersection.x <= s2.p1.x)
) &&
(
(s2.p1.y <= intersection.y && intersection.y <= s2.p2.y) ||
(s2.p2.y <= intersection.y && intersection.y <= s2.p1.y)
)
)
return intersection;
return null;
};
Here's my answer. I have tested it to be accurate by making a loop that checks that the answer it gives is the same as the one given by the Boost geometry library and they agree on each test, though the one that I have written below is much much faster than the one in Boost. The test makes every possible line segment where x is and integer in [-3,2] and y is an integer in [-3,2], for all possible pairs of line segments.
The code below considers line segments that touch at endpoints to be intersecting.
T-shaped intersections are also considered intersecting. The code is in c++ but would be easily adaptable to any language. It's based on a different stackoverflow answer but that answer did not handle endpoints correctly.
It uses the cross product method, which can report if a point is to the left or to the right of a given ray.
There are some optimizations to be made in the math but doing them showed no performance improvement over compilation with g++ -O2 and sometime the performance even decreased! The compiler is able to do those optimizations so I prefered to leave the code readable.
// is_left(): tests if a point is Left|On|Right of an infinite line.
// Input: three points p0, p1, and p2
// Return: >0 for p2 left of the line through p0 and p1
// =0 for p2 on the line
// <0 for p2 right of the line
// See: Algorithm 1 "Area of Triangles and Polygons"
// This is p0p1 cross p0p2.
extern inline coordinate_type_fp is_left(point_type_fp p0, point_type_fp p1, point_type_fp p2) {
return ((p1.x() - p0.x()) * (p2.y() - p0.y()) -
(p2.x() - p0.x()) * (p1.y() - p0.y()));
}
// Is x between a and b, where a can be lesser or greater than b. If
// x == a or x == b, also returns true. */
extern inline coordinate_type_fp is_between(coordinate_type_fp a,
coordinate_type_fp x,
coordinate_type_fp b) {
return x == a || x == b || (a-x>0) == (x-b>0);
}
// https://stackoverflow.com/questions/563198/how-do-you-detect-where-two-line-segments-intersect
extern inline bool is_intersecting(const point_type_fp& p0, const point_type_fp& p1,
const point_type_fp& p2, const point_type_fp& p3) {
const coordinate_type_fp left012 = is_left(p0, p1, p2);
const coordinate_type_fp left013 = is_left(p0, p1, p3);
const coordinate_type_fp left230 = is_left(p2, p3, p0);
const coordinate_type_fp left231 = is_left(p2, p3, p1);
if (p0 != p1) {
if (left012 == 0) {
if (is_between(p0.x(), p2.x(), p1.x()) &&
is_between(p0.y(), p2.y(), p1.y())) {
return true; // p2 is on the line p0 to p1
}
}
if (left013 == 0) {
if (is_between(p0.x(), p3.x(), p1.x()) &&
is_between(p0.y(), p3.y(), p1.y())) {
return true; // p3 is on the line p0 to p1
}
}
}
if (p2 != p3) {
if (left230 == 0) {
if (is_between(p2.x(), p0.x(), p3.x()) &&
is_between(p2.y(), p0.y(), p3.y())) {
return true; // p0 is on the line p2 to p3
}
}
if (left231 == 0) {
if (is_between(p2.x(), p1.x(), p3.x()) &&
is_between(p2.y(), p1.y(), p3.y())) {
return true; // p1 is on the line p2 to p3
}
}
}
if ((left012 > 0) == (left013 > 0) ||
(left230 > 0) == (left231 > 0)) {
if (p1 == p2) {
return true;
}
return false;
} else {
return true;
}
}
The test code:
BOOST_AUTO_TEST_CASE(small, *boost::unit_test::disabled()) {
for (double x0 = -3; x0 < 3; x0++) {
for (double y0 = -3; y0 < 3; y0++) {
for (double x1 = -3; x1 < 3; x1++) {
for (double y1 = -3; y1 < 3; y1++) {
for (double x2 = -3; x2 < 3; x2++) {
for (double y2 = -3; y2 < 3; y2++) {
for (double x3 = -3; x3 < 3; x3++) {
for (double y3 = -3; y3 < 3; y3++) {
point_type_fp p0{x0, y0};
point_type_fp p1{x1, y1};
point_type_fp p2{x2, y2};
point_type_fp p3{x3, y3};
linestring_type_fp ls0{p0,p1};
linestring_type_fp ls1{p2,p3};
BOOST_TEST_INFO("intersection: " << bg::wkt(ls0) << " " << bg::wkt(ls1));
BOOST_CHECK_EQUAL(
path_finding::is_intersecting(p0, p1, p2, p3),
bg::intersects(ls0, ls1));
}
}
}
}
}
}
}
}
}
in the example which is given in the book "Computer Graphics for Java Programmers, Second Edition"
there is transformation with view vector
private void shiftToOrigin()
{ float xwC = 0.5F * (xMin + xMax),
ywC = 0.5F * (yMin + yMax),
zwC = 0.5F * (zMin + zMax);
int n = w.size();
for (int i=1; i<n; i++)
if (w.elementAt(i) != null)
{ ((Point3D)w.elementAt(i)).x -= xwC;
((Point3D)w.elementAt(i)).y -= ywC;
((Point3D)w.elementAt(i)).z -= zwC;
}
float dx = xMax - xMin, dy = yMax - yMin, dz = zMax - zMin;
rhoMin = 0.6F * (float) Math.sqrt(dx * dx + dy * dy + dz * dz);
rhoMax = 1000 * rhoMin;
rho = 3 * rhoMin;
}
private void initPersp()
{
float costh = (float)Math.cos(theta),
sinth = (float)Math.sin(theta),
cosph = (float)Math.cos(phi),
sinph = (float)Math.sin(phi);
v11 = -sinth; v12 = -cosph * costh; v13 = sinph * costh;
v21 = costh; v22 = -cosph * sinth; v23 = sinph * sinth;
v32 = sinph; v33 = cosph;
v43 = -rho;
}
float eyeAndScreen(Dimension dim)
// Called in paint method of Canvas class
{ initPersp();
int n = w.size();
e = new Point3D[n];
vScr = new Point2D[n];
float xScrMin=1e30F, xScrMax=-1e30F,
yScrMin=1e30F, yScrMax=-1e30F;
for (int i=1; i<n; i++)
{
Point3D P = (Point3D)(w.elementAt(i));
if (P == null)
{ e[i] = null; vScr[i] = null;
}
else
{ float x = v11 * P.x + v21 * P.y;
float y = v12 * P.x + v22 * P.y + v32 * P.z;
float z = v13 * P.x + v23 * P.y + v33 * P.z + v43;
Point3D Pe = e[i] = new Point3D(x, y, z);
float xScr = -Pe.x/Pe.z, yScr = -Pe.y/Pe.z;
vScr[i] = new Point2D(xScr, yScr);
if (xScr < xScrMin) xScrMin = xScr;
if (xScr > xScrMax) xScrMax = xScr;
if (yScr < yScrMin) yScrMin = yScr;
if (yScr > yScrMax) yScrMax = yScr;
}
}
float rangeX = xScrMax - xScrMin, rangeY = yScrMax - yScrMin;
d = 0.95F * Math.min(dim.width/rangeX, dim.height/rangeY); //d burada
imgCenter = new Point2D(d * (xScrMin + xScrMax)/2,
d * (yScrMin + yScrMax)/2);
for (int i=1; i<n; i++)
{
if (vScr[i] != null){vScr[i].x *= d; vScr[i].y *= d;}
}
return d * Math.max(rangeX, rangeY);
// Maximum screen-coordinate range used in CvHLines for HP-GL
}
here float xScr = -Pe.x/Pe.z, yScr = -Pe.y/Pe.z; when we divide x and y with z that give as a perspective view if we don't divide it with z the view will be parallel(orthogonal)
this is OK but if we want to this parallel view coordinates with hidden line algorithm in same book it calculates lines wrongly. I couldn't find where problem is. What can cause this problem?
here hidden line algorithm:
private void lineSegment(Graphics g, Point3D Pe, Point3D Qe,
Point2D PScr, Point2D QScr, int iP, int iQ, int iStart)
{
double u1 = QScr.x - PScr.x; //t
double u2 = QScr.y - PScr.y; //t
double minPQx = Math.min(PScr.x, QScr.x);//t
double maxPQx = Math.max(PScr.x, QScr.x);//t
double minPQy = Math.min(PScr.y, QScr.y);//t
double maxPQy = Math.max(PScr.y, QScr.y);//t
double zP = Pe.z; //t
double zQ = Qe.z; //t
double minPQz = Math.min(zP, zQ);//t
Point3D[] e = obj.getE();//e eye
Point2D[] vScr = obj.getVScr(); //vscr screen
for (int i=iStart; i<nTria; i++)//t
{
Tria t = tr[i];
int iA = t.iA, iB = t.iB, iC = t.iC;
Point2D AScr = vScr[iA], BScr = vScr[iB], CScr = vScr[iC];
// 1. Minimax test for x and y screen coordinates: //t
if (maxPQx <= AScr.x && maxPQx <= BScr.x && maxPQx <= CScr.x
|| minPQx >= AScr.x && minPQx >= BScr.x && minPQx >= CScr.x
|| maxPQy <= AScr.y && maxPQy <= BScr.y && maxPQy <= CScr.y
|| minPQy >= AScr.y && minPQy >= BScr.y && minPQy >= CScr.y)
continue;
// 2. Test if PQ is an edge of ABC: //t
if ((iP == iA || iP == iB || iP == iC) &&
(iQ == iA || iQ == iB || iQ == iC))
continue;
// 3. Test if PQ is clearly nearer than ABC://t
Point3D Ae = e[iA], Be = e[iB], Ce = e[iC];
double zA = Ae.z, zB = Be.z, zC = Ce.z;
if (minPQz >= zA && minPQz >= zB && minPQz >= zC)
continue;
// 4. Do P and Q (in 2D) lie in a half plane defined
// by line AB, on the side other than that of C?
// Similar for the edges BC and CA.
double eps = 0.1; // Relative to numbers of pixels //t
if (Tools2D.area2(AScr, BScr, PScr) < eps &&
Tools2D.area2(AScr, BScr, QScr) < eps ||
Tools2D.area2(BScr, CScr, PScr) < eps &&
Tools2D.area2(BScr, CScr, QScr) < eps ||
Tools2D.area2(CScr, AScr, PScr) < eps &&
Tools2D.area2(CScr, AScr, QScr) < eps)
continue;
// 5. Test (2D) if A, B and C lie on the same side
// of the infinite line through P and Q://t
double PQA = Tools2D.area2(PScr, QScr, AScr);
double PQB = Tools2D.area2(PScr, QScr, BScr);
double PQC = Tools2D.area2(PScr, QScr, CScr);
if (PQA < +eps && PQB < +eps && PQC < +eps ||
PQA > -eps && PQB > -eps && PQC > -eps)
continue;
// 6. Test if neither P nor Q lies behind the
// infinite plane through A, B and C://t
int iPol = refPol[i];
Polygon3D pol = (Polygon3D)polyList.elementAt(iPol);
double a = pol.getA(), b = pol.getB(), c = pol.getC(),
h = pol.getH(), eps1 = 1e-5 * Math.abs(h),
hP = a * Pe.x + b * Pe.y + c * Pe.z,
hQ = a * Qe.x + b * Qe.y + c * Qe.z;
if (hP > h - eps1 && hQ > h - eps1)
continue;
// 7. Test if both P and Q behind triangle ABC://t
boolean PInside =
Tools2D.insideTriangle(AScr, BScr, CScr, PScr);
boolean QInside =
Tools2D.insideTriangle(AScr, BScr, CScr, QScr);
if (PInside && QInside)
return;
// 8. If P nearer than ABC and inside, PQ visible;//t
// the same for Q:
double h1 = h + eps1;
boolean PNear = hP > h1, QNear = hQ > h1;
if (PNear && PInside || QNear && QInside)
continue;
// 9. Compute the intersections I and J of PQ
// with ABC in 2D.
// If, in 3D, such an intersection lies in front of
// ABC, this triangle does not obscure PQ.
// Otherwise, the intersections lie behind ABC and
// this triangle obscures part of PQ:
double lambdaMin = 1.0, lambdaMax = 0.0;
for (int ii=0; ii<3; ii++)
{ double v1 = BScr.x - AScr.x, v2 = BScr.y - AScr.y,
w1 = AScr.x - PScr.x, w2 = AScr.y - PScr.y,
denom = u2 * v1 - u1 * v2;
if (denom != 0)
{ double mu = (u1 * w2 - u2 * w1)/denom;
// mu = 0 gives A and mu = 1 gives B.
if (mu > -0.0001 && mu < 1.0001)
{ double lambda = (v1 * w2 - v2 * w1)/denom;
// lambda = PI/PQ
// (I is point of intersection)
if (lambda > -0.0001 && lambda < 1.0001)
{ if (PInside != QInside &&
lambda > 0.0001 && lambda < 0.9999)
{ lambdaMin = lambdaMax = lambda;
break;
// Only one point of intersection
}
if (lambda < lambdaMin) lambdaMin = lambda;
if (lambda > lambdaMax) lambdaMax = lambda;
}
}
}
Point2D temp = AScr; AScr = BScr;
BScr = CScr; CScr = temp;
}
float d = obj.getD();
if (!PInside && lambdaMin > 0.001)
{ double IScrx = PScr.x + lambdaMin * u1,
IScry = PScr.y + lambdaMin * u2;
// Back from screen to eye coordinates:
double zI = 1/(lambdaMin/zQ + (1 - lambdaMin)/zP),
xI = -zI * IScrx / d, yI = -zI * IScry / d;
if (a * xI + b * yI + c * zI > h1) continue;
Point2D IScr = new Point2D((float)IScrx, (float)IScry);
if (Tools2D.distance2(IScr, PScr) >= 1.0)
lineSegment(g, Pe, new Point3D(xI, yI, zI), PScr,
IScr, iP, -1, i + 1);
}
if (!QInside && lambdaMax < 0.999)
{ double JScrx = PScr.x + lambdaMax * u1,
JScry = PScr.y + lambdaMax * u2;
double zJ =
1/(lambdaMax/zQ + (1 - lambdaMax)/zP),
xJ = -zJ * JScrx / d, yJ = -zJ * JScry / d;
if (a * xJ + b * yJ + c * zJ > h1) continue;
Point2D JScr = new Point2D((float)JScrx, (float)JScry);
if (Tools2D.distance2(JScr, QScr) >= 1.0)
lineSegment(g, Qe, new Point3D(xJ, yJ, zJ),
QScr, JScr, iQ, -1, i + 1);
}
return;
// if no continue-statement has been executed
}
drawLine(g, PScr.x, PScr.y, QScr.x, QScr.y);
}
}
I posted something similar yesterday, but got nothing. I spent a few hours today problem-solving, but didn't progress any.
I'm using Processing (the language) and trying to implement a method that draws a line between two points. (I don't want to use the library's line() method.)
My lineCreate method works great for positive slopes, but fails with negative slopes. Can you help figure out why?
Here's the lineCreate() code:
void createLine(int x0, int y0, int x1, int y1){
//...
// Handle slanted lines...
double tempDX = x1 - x0;
double tempDY = y1 - y0; // Had to create dx and dy as doubles because typecasting dy/dx to a double data type wasn't working.
double m = (-tempDY / tempDX); // m = line slope. (Note - The dy value is negative
int deltaN = (2 * -dx); // deltaX is the amount to increment d after choosing the next pixel on the line.
int deltaNE = (2 * (-dy - dx)); // ...where X is the direction moved for that next pixel.
int deltaE = (2 * -dy); // deltaX variables are used below to plot line.
int deltaSE = (2 * (dy + dx));
int deltaS = (2 * dx);
int x = x0;
int y = y0;
int d = 0; // d = Amount d-value changes from pixel to pixel. Depends on slope.
int region = 0; // region = Variable to store slope region. Different regions require different formulas.
if(m > 1){ // if-statement: Initializes d, depending on the slope of the line.
d = -dy - (2 * dx); // If slope is 1-Infiniti. -> Use NE/N initialization for d.
region = 1;
}
else if(m == 1)
region = 2;
else if(m > 0 && m < 1){
d = (2 * -dy) - dx; // If slope is 0-1 -> Use NE/E initialization for d.
region = 3;
}
else if(m < 0 && m > -1){
d = (2 * dy) + dx; // If slope is 0-(-1) -> Use E/SE initliazation for d.
region = 4;
}
else if(m == -1)
region = 5;
else if(m < -1){
d = dy + (2 * dx); // If slope is (-1)-(-Infiniti) -> Use SE/S initialization for d.
region = 6;
}
while(x < x1){ // Until points are connected...
if(region == 1){ // If in region one...
if(d <= 0){ // and d<=0...
d += deltaNE; // Add deltaNE to d, and increment x and y.
x = x + 1;
y = y - 1;
}
else{
d += deltaN; // If d > 0 -> Add deltaN, and increment y.
y = y - 1;
}
}
else if(region == 2){
x = x + 1;
y = y - 1;
}
else if(region == 3){ // If region two...
if(d <= 0){
d += deltaE;
x = x + 1;
}
else{
d += deltaNE;
x = x + 1;
y = y - 1;
}
}
else if(region == 4){ // If region three...
if(d <= 0){
d += deltaSE;
x = x + 1;
y = y + 1;
}
else{
d += deltaE;
x = x + 1;
}
}
else if(region == 5){
x = x + 1;
y = y + 1;
}
else if(region == 6){ // If region four...
if(d <= 0){
d += deltaSE;
x = x + 1;
y = y + 1;
}
else{
d += deltaS;
y = y + 1;
}
}
point(x, y); // Paints new pixel on line going towards (x1,y1).
}
return;
}
Have a look at this page. It explains the whole theory behind line drawing with code examples.
There are a number of known algorithm for line drawing. Read about them here.