This is my first question here on stackoverflow, so i hope i got all things right. For an java project i need to use an octree for raytracing. I already created an simple octree (without neighbour information or something) and sorted the triangles of the object meshs into the AABB's of the octree. Now I would like to make an easy traversation through the tree for every ray. (it should be really easy because the time to finish this project is very short). The basic algorithmn is the following:
Start with the first node
if this node is hit, remember the place of the intersection in a sorted list
if this node has children check if the child boxes are hit and write every intersection point in a sorted list
start with the child box with the nearest intersection point
if this box has children too see 4)
if a node doesn't have any childs check every triangle in this
box against the ray
if a triangle is hit get the color of triangle (with shading and
everything) and draw it on the screen
Unfortunately my current implementation seems to have a "bug" in the intersection calculation (ray vs ABBB). I check if any side of the AABB is hit and remember the clostest ip (smallest distance from ray origin).
Here is the Code for this function in my BoundingBox Class:
public HitResult intersects6(Ray ray) {
double t;
Vec3d ip = new Vec3d();
HitResult finalHitResult = null;
// front xy
if (Math.abs(ray.direction.z) > Helper.EPSYLON) {
t = (vmax.z - ray.origin.z) / ray.direction.z;
ip.x = ray.origin.x + t * ray.direction.x;
ip.y = ray.origin.y + t * ray.direction.y;
ip.z = vmax.z;
if ((ip.x >= vmin.x) && (ip.x <= vmax.x) && (ip.y >= vmin.y) && (ip.y <= vmax.y)) {
// here is an intersection
double distance = Vec3d.distance(ray.origin, ip);
finalHitResult = new HitResult(ip, distance);
}
}
// back xy
if (Math.abs(ray.direction.z) > Helper.EPSYLON) {
t = (vmin.z + ray.origin.z) / -ray.direction.z;
ip.x = ray.origin.x + t * ray.direction.x;
ip.y = ray.origin.y + t * ray.direction.y;
ip.z = vmin.z;
if ((ip.x >= vmin.x) && (ip.x <= vmax.x) && (ip.y >= vmin.y) && (ip.y <= vmax.y)) {
double distance = Vec3d.distance(ray.origin, ip);
if (finalHitResult!= null) {
if(distance < finalHitResult.distance)
finalHitResult.distance = distance;
finalHitResult.point = ip;
}
else
finalHitResult = new HitResult(ip, distance);
}
}
// Side Right
if (Math.abs(ray.direction.x) > Helper.EPSYLON) {
t = (vmax.x - ray.origin.x) / ray.direction.x;
ip.y = ray.origin.y + t * ray.direction.y;
ip.z = ray.origin.z + t * ray.direction.z;
ip.x = vmax.x;
if ((ip.y >= vmin.y) && (ip.y <= vmax.y) && (ip.z >= vmin.z) && (ip.z <= vmax.z)) {
double distance = Vec3d.distance(ray.origin, ip);
if (finalHitResult!= null) {
if(distance < finalHitResult.distance)
finalHitResult.distance = distance;
finalHitResult.point = ip;
}
else
finalHitResult = new HitResult(ip, distance);
}
}
// Side Left
if (Math.abs(ray.direction.x) > Helper.EPSYLON) {
t = (vmin.x + ray.origin.x) / -ray.direction.x;
ip.y = ray.origin.y + t * ray.direction.y;
ip.z = ray.origin.z + t * ray.direction.z;
ip.x = vmin.x;
if ((ip.y >= vmin.y) && (ip.y <= vmax.y) && (ip.z >= vmin.z) && (ip.z <= vmax.z)) {
double distance = Vec3d.distance(ray.origin, ip);
if (finalHitResult!= null) {
if(distance < finalHitResult.distance)
finalHitResult.distance = distance;
finalHitResult.point = ip;
}
else
finalHitResult = new HitResult(ip, distance);
}
}
// Top
if (Math.abs(ray.direction.y) > Helper.EPSYLON) {
t = (vmax.y - ray.origin.y) / ray.direction.y;
ip.x = ray.origin.x + t * ray.direction.x;
ip.z = ray.origin.z + t * ray.direction.z;
ip.y = vmax.y;
if ((ip.x >= vmin.x) && (ip.x <= vmax.x) && (ip.z >= vmin.z) && (ip.z <= vmax.z)) {
double distance = Vec3d.distance(ray.origin, ip);
if (finalHitResult!= null) {
if(distance < finalHitResult.distance)
finalHitResult.distance = distance;
finalHitResult.point = ip;
}
else
finalHitResult = new HitResult(ip, distance);
}
}
// Bottom
if (Math.abs(ray.direction.y) > Helper.EPSYLON) {
t = (vmin.y + ray.origin.y) / -ray.direction.y;
ip.x = ray.origin.x + t * ray.direction.x;
ip.z = ray.origin.z + t * ray.direction.z;
ip.y = vmin.y;
if ((ip.x >= vmin.x) && (ip.x <= vmax.x) && (ip.z >= vmin.z) && (ip.z <= vmax.z)) {
double distance = Vec3d.distance(ray.origin, ip);
if (finalHitResult!= null) {
if(distance < finalHitResult.distance)
finalHitResult.distance = distance;
finalHitResult.point = ip;
}
else
finalHitResult = new HitResult(ip, distance);
}
}
return finalHitResult;
I guess this is not the best way to do it. In my first implementation i just used the t-values and compared them (to find the box i would like to visit next). But the problem was the same. Some intersections could not be found.
I also checked out the intersection method here:
https://code.google.com/p/3d-workspace/source/browse/trunk/MathLibrary/Bounding/BoundingBox.cpp?r=17
but I can't see how to get the intersection point with this code (or even any t-value). Moreover i tested the slab method like descripted here:
http://tavianator.com/2011/05/fast-branchless-raybounding-box-intersections/
but this seems to also miss some intersections, i don't know why:
public double[] intersects3(Ray ray) {
double Tnear = -1e30;
double Tfar = 1e30;
// First, check slab in X.
if (Math.abs(ray.direction.x) < 0.0) {
// Ray is parallel to X, but starts outside. Fail.
if (ray.origin.x < vmin.x || ray.origin.x > vmax.x) {
return null;
}
} else {
double Ta = ((vmin.x - ray.origin.x) / ray.direction.x), Tb = (vmax.x - ray.origin.x) / ray.direction.x;
double T1 = Math.min(Ta, Tb);
double T2 = Math.max(Ta, Tb);
if (T1 > Tnear)
Tnear = T1;
if (T2 < Tfar)
Tfar = T2;
if (Tnear > Tfar)
return null;
if (Tfar < 0)
return null;
}
// Then check slab in Y.
if (Math.abs(ray.direction.y) < 0.0) {
// Ray is parallel to X, but starts outside. Fail.
if (ray.origin.y < vmin.y || ray.origin.y > vmax.y) {
return null;
}
} else {
double Ta = (vmin.y - ray.origin.y) / ray.direction.y, Tb = (vmax.y - ray.origin.y) / ray.direction.y;
double T1 = Math.min(Ta, Tb);
double T2 = Math.max(Ta, Tb);
if (T1 > Tnear)
Tnear = T1;
if (T2 < Tfar)
Tfar = T2;
if (Tnear > Tfar)
return null;
if (Tfar < 0)
return null;
}
// Then check slab in Z.
if (Math.abs(ray.direction.z) < 0.0) {
// Ray is parallel to X, but starts outside. Fail.
if (ray.origin.z < vmin.z || ray.origin.z > vmax.z) {
return null;
}
} else {
double Ta = (vmin.z - ray.origin.z) / ray.direction.z, Tb = (vmax.z - ray.origin.z) / ray.direction.z;
double T1 = Math.min(Ta, Tb);
double T2 = Math.max(Ta, Tb);
if (T1 > Tnear)
Tnear = T1;
if (T2 < Tfar)
Tfar = T2;
if (Tnear > Tfar)
return null;
if (Tfar < 0)
return null;
}
// If we have survived this far, the test passed.
return new double[] { Tnear, Tfar };
}
Maybe I'm too stupid for raytracing at all.
But my actual question is:
Is it possible to use the t-values to compare which box has the closest intersection point ? And if yes, how can i get this t-values? Or what could i do to make the first code snipped work? (so far i would be happy with ANY working solution, even if this solution is very slow )
Thanks in advance.
Maybe this could be helpful:
http://chiranjivi.tripod.com/octrav.html
I've tried to implement the idea for a quadtree:
https://github.com/alexroat/quadtree-traversal
Related
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);
}
}
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'm trying to implement rope swinging in my platformer, following this tutorial. Instead of swing on the rope, the player looks like he's sliding down a slope: he moves very slowly towards the bottom.
This is what it looks like now:
Instead, I want the player to have more natural movement, like he's really swinging on the rope.
This is the update method from my player class:
#Override
public final void update() {
setPosition(getNextPosition());
if (direction == Direction.LEFT && moving) {
getVelocity().x = -WALK_SPEED;
} else if (getVelocity().x < 0) {
getVelocity().x *= COEF_FRIC;
}
if (direction == Direction.RIGHT && moving) {
getVelocity().x = WALK_SPEED;
} else if (getVelocity().x > 0) {
getVelocity().x *= COEF_FRIC;
}
checkAsleep();
animations.update();
if (ropePoint != null) {
//getCenter() returns the center position of the player
if (getCenter().toPoint().distanceSq(ropePoint) > ROPE_LENGTH * ROPE_LENGTH) {
final Vec2D oldPosition = getCenter();
final Vec2D oldVelocity = getVelocity();
final Vec2D ropePosition = new Vec2D(ropePoint);
setCenter((oldPosition.subtract(ropePosition).unit().multiply(ROPE_LENGTH).add(ropePosition)));
setVelocity(oldPosition.subtract(getCenter()).unit().multiply(oldVelocity));
}
}
}
This is my implementation of getNextPosition(), if it is needed.
public final Vec2D getNextPosition() {
final int currCol = (int) (getX() / Tile.SIZE);
final int currRow = (int) (getY() / Tile.SIZE);
final double destX = getX() + moveData.velocity.x;
final double destY = getY() + moveData.velocity.y;
double tempX = getX();
double tempY = getY();
Corners solidCorners = getCornersAreSolid(getX(), destY);
boolean topLeft = solidCorners.topLeft;
boolean topRight = solidCorners.topRight;
boolean bottomLeft = solidCorners.bottomLeft;
boolean bottomRight = solidCorners.bottomRight;
framesSinceLastTopCollision += 1;
framesSinceLastBottomCollision += 1;
framesSinceLastLeftCollision += 1;
framesSinceLastRightCollision += 1;
if (moveData.velocity.y < 0) {
if (topLeft || topRight) {
moveData.velocity.y = 0;
tempY = currRow * Tile.SIZE;
framesSinceLastTopCollision = 0;
} else {
tempY += moveData.velocity.y;
}
} else if (moveData.velocity.y > 0) {
if (bottomLeft || bottomRight) {
moveData.velocity.y = 0;
tempY = (currRow + 1) * Tile.SIZE - moveData.collisionBox.getHeight() % Tile.SIZE - 1;
framesSinceLastBottomCollision = 0;
} else {
tempY += moveData.velocity.y;
}
}
solidCorners = getCornersAreSolid(destX, getY());
topLeft = solidCorners.topLeft;
topRight = solidCorners.topRight;
bottomLeft = solidCorners.bottomLeft;
bottomRight = solidCorners.bottomRight;
if (moveData.velocity.x < 0) {
if (topLeft || bottomLeft) {
moveData.velocity.x = 0;
tempX = currCol * Tile.SIZE;
framesSinceLastLeftCollision = 0;
} else {
tempX += moveData.velocity.x;
}
}
if (moveData.velocity.x > 0) {
if (topRight || bottomRight) {
moveData.velocity.x = 0;
tempX = (currCol + 1) * Tile.SIZE - moveData.collisionBox.getWidth() % Tile.SIZE - 1;
framesSinceLastRightCollision = 0;
} else {
tempX += moveData.velocity.x;
}
}
return new Vec2D(tempX, tempY);
}
What should I change in this code to get natural movement?
My first guess is that the problem lies in that first if statement:
if (direction == Direction.LEFT && moving) {
getVelocity().x = -WALK_SPEED;
} else if (getVelocity().x < 0) {
getVelocity().x *= COEF_FRIC;
}
If the first thing is true, you're going to constantly be setting the velocity to walking pace, which doesn't make sense when your guy is swinging on a rope. He should be speeding up as he goes down and slowing down on the way up.
If the first thing is false, then since he is going left, you're definitely going to go into the else if statement, and he'll be slowed down by friction. I don't see where you set that, but it seems to still be the friction he has on the ground, which would seem to explain why he's all stuttery and looks more like he's sliding than falling.
You might want to add different states instead of just "moving", (perhaps jumping, swinging, walking, running, stopped) and vary how he behaves while doing each of those things.
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);
}
}
how do I calculate the font size of a TextView so that always occupy a certain percentage of the screen?
now I spit it out:
.....
densityNormal = Float.parseFloat("1.0");
densitySub = Float.parseFloat("0.75");
densityIper = Float.parseFloat("1.5");
densityExtra = Float.parseFloat("2.0");
.....
textviewSample.setTextSize(getHeightPercentage(context,30));
.....
private float getHeightPercentage(Context context, int percentage) {
if (percentage > 0 && percentage < 100) {
float appHeight = context.getApplicationContext().getResources()
.getDisplayMetrics().heightPixels;
float appSPDensity = context.getApplicationContext().getResources()
.getDisplayMetrics().scaledDensity;
if (Float.compare(appSPDensity, densitySub) == 0) {
appHeight = appHeight + ((appHeight * 25) / 100);
} else if (Float.compare(appSPDensity, densityIper) == 0) {
appHeight = ((appHeight * 50) / 100) - appHeight;
} else if (Float.compare(appSPDensity, densityExtra) == 0) {
appHeight = ((appHeight * 200) / 100) - appHeight;
}
return new Float((appHeight * percentage) / 100);
} else
return -1;
}
but I can not integrate the different density of the screen,have you any suggestions?8y3