import java.lang.Math;
import java.awt.*
public class Triangle implements Shape
{
java.awt.Point a;
java.awt.Point b;
java.awt.Point c;
public Triangle(java.awt.Point a, java.awt.Point b, java.awt.Point c)
{
this.a = a;
this.b = b;
this.c = c;
}
public double getArea( )
{
double area;
return area = Math.abs((a-c)*(b-a)-(a-b)*(c-a));
} ...
http://upload.wikimedia.org/math/f/e/5/fe56529cdaaaa9bb2f71c1ad8a1a454f.png <--area formula
I am trying to calculate the area of a triangle from 3 points (x,y) from a 2D Cartesian coordinate system. I'm assuming that my above formula correctly yields the area of a triangle (if not, please correct me) but my compiler says "operator - cannot be applied to java.awt.Point,java.awt.Point". I'm assuming it's saying this because you cannot subtract points from each other, but each value in the formula is either an x or y value, not a point. How can I fix my code so this would work?
Thanks!
According to Wikipedia, you formula is correct. The article contains lots of useful and clear data.
According to the java.awt.point documentation, you should use the getX() and getY() methods, which return the coordinate value of a point.
That is,
Should be expressed as:
Math.abs((a.getX()-c.getX())*(b.getY()-a.getY())-
(a.getX()-b.getX())*(c.getY()-a.getY()))*0.5;
It is probably not such a good practice to use point.x, because you shouldn't access an object's variable if you have a getter method that does that. This is the one aspect of separation between interface and implementation: the data point.x might be stored in many forms, not just int; The interface method assures that you'll get an int every time you use it.
compiler is telling you the exact right thing.
Math.abs((a-c)*(b-a)-(a-b)*(c-a)
you forgot .x in a.x .y in b.y etc. that is (a.x - c.x)* ...
Update: I didn't notice that OP had linked to a formula, that's why I looked up this one and coded it. You should use the other formula as this one involves more calculations (including 4 calls to sqrt, I think that would be heavy).
Using Heron's formula
double distance(Point a, Point b)
{
double dx = a.x - b.x;
double dy = a.y - b.y;
return Math.sqrt(dx * dx + dy * dy);
}
double getArea()
{
double ab = distance(a, b);
double bc = distance(c, b);
double ca = distance(a, c);
double s = (ab + bc + ca) / 2;
return Math.sqrt(s * (s - ab) * (s - bc) * (s - ca))
}
As the linked formula says, don't calculate with the points but with their x- and y-values. I'll leave it to you (it's homework!) to do that in java.
And don't forget to divide by 2.
Use a.x - c.x etc.
Just read the Javadoc:
http://java.sun.com/j2se/1.5.0/docs/api/java/awt/Point.html
The underlying problem: In Java, operators like '+' and '-' are only allowed for primitive types (like byte, int, long) but not for objects (in general) and arrays.
Other languages allow for operator overloading, so in c++ you could define a '+' operation for Point objects and there your initial idea would compile and run. But that is not possible in Java.
The only exceptions are String (it's allowed to 'add' String objects) and the primitive wrappers like Integer and Double in Java 1.5+ (autoboxing converts them back to primitives)
Related
This question already has answers here:
Int division: Why is the result of 1/3 == 0?
(19 answers)
Closed 3 years ago.
I recompiled my graphing application for wear OS and something broke. The app displays a grid and a waveform, but the waveform is getting mis constructed. In wear, the grid is more coarse and this error is evident. I have shown the original code and a modified
sequence below.
// scale Y coordinate. Input, elevation in feet.
// Output, y position of elevation in screen coordinate
static float scaleY(double elevation) {
double a, b, c, offsetFromTopFeet, pixelRange, feetRange, pixelsPerFoot,offsetFromTopPixels;
// original coding
a = maxY - elevation; //point in terms of feet within vert scale.
b = (bottom - top) / (maxY - minY);
c = top + (float) (a * b);
// return (float)c;
// new coding
offsetFromTopFeet = maxY - elevation; // a
pixelRange = bottom - top;
feetRange = maxY - minY;
pixelsPerFoot = pixelRange / feetRange; // b
offsetFromTopPixels = top + offsetFromTopFeet * pixelsPerFoot;
return (float) offsetFromTopPixels;
}
The calculation of b in the original coding returns an integer result even though the variable is a double. This is what distorts the waveform. In the reconstructed code shown underneath the variable pixelsPerFoot is calculated correctly, and the graph displays correctly. I have used this routine in android application for numerous years and either I never noticed the problem, the finer grid covered it up, or something else?
My question is why does the b calculation return an integer, but the pixelsPerFoot return the correct type? Is this a programming error?
The expression (bottom - top) / (maxY - minY); is of type int, since the subtraction of two ints is an int, and the division of an int by an int is also an int. The type of variable the result is assigned to is irrelevant; the calculation is performed using integer arithmetic and then converted to a floating point value after truncation.
Cast at least one of the variables to a floating point type, and the expression will be evaluated using a floating point division.
For this line of code:
b = (bottom - top) / (maxY - minY);
Where do bottom,top,maxY, andminY` come from? I don't see them defined in your posted code.
If they are integers, then of course b will end up with an integer value (stored in a double, but still integer). The left-hand side of an assignment doesn't change the numeric context of the right side. The right side is purely integer if all of the variables are integers.
If you do this:
b = (double) (bottom - top) / (maxY - minY);
That will give you the desired results.
all components being int you need a cast, for example (double) feetRange in denominator
I am trying to convert some old DSP code written in C into Java and later to C#. I do not understand what the argument "double (*Window)(double)" means and how to reference it in the Java code. The following function has me unsure what to do.
void WinFirI(float LowOmega, float UppOmega,
float *Shape, int Len, double (*Window)(double), float shift)
{ int i; double time,phase,shape;
// printf("WinFirI: %5.3f %5.3f %d\n",LowOmega,UppOmega,Len);
for(i=0; i<Len; i++)
{ time=i+(1.0-shift)-(float)Len/2; phase=2*M_PI*time/Len;
if(time==0) shape=UppOmega-LowOmega;
else shape=(sin(UppOmega*time)-sin(LowOmega*time))/time;
// printf("%2d %5.1f %5.2f %7.4f %7.4f\n",i,time,phase,shape,(*Window) (phase));
Shape[i]=shape*(*Window)(phase)/M_PI; }
}
So far I have written this:
public void WinFirI(float LowOmega, float UppOmega,
float[] Shape, int Len, double[] Window, float shift) {
double time;
double phase;
double shape;
// printf("WinFirI: %5.3f %5.3f %d\n",LowOmega,UppOmega,Len);
for(int i=0; i<Len; i++) {
time = i +(1.0-shift) - (float)Len/2;
phase = 2 * Math.PI * time / Len;
if(time==0) {
shape = UppOmega - LowOmega;
}
else {
shape=(Math.sin(UppOmega*time) - Math.sin(LowOmega*time)) / time;
}
// printf("%2d %5.1f %5.2f %7.4f %7.4f\n",i,time,phase,shape, (*Window)(phase));
//Shape[i]=shape*(*Window)(phase)/M_PI;
Shape[i] = shape * Window[phase]/Math.PI;
}
}
Pointer to function with parameter double returning double.
As an added note, implementing this function pointer behavior in Java would be done through an anonymous class/interface.
double Window(double param);
In Java would be:
interface WindowFnWrapper {
double Window(double param);
}
Then the function signature would be:
public void WinFirI(float LowOmega, float UppOmega,
float[] Shape, int Len, WindowFnWrapper WindowWrapper, float shift)
Every time you call Window() you would replace it with WindowWrapper.Window().
The declaration double (*Window)(double) declares a parameter Window, whose value is a pointer to a function. That function must be one which takes a single double as an argument, and returns a double.
In your C code, (well, actually the commented-out part), that pointer gets dereferenced, and the function called, passing phase as its argument. That is, the value of the expression (*Window) (phase) is just the result of calling the function whose address you passed in.
If you're using Java 8 or above, the nearest available equivalent is the Function generic class, from the java.util.function package. So if you write
import java.util.function.Function;
then you can declare the parameter as
Function<Double,Double> window
and use it as
window.apply(phase);
The only real difference between this and your C code is that the type parameters to Java generics can't be primitive types such as double.
Double is a reference type that works a bit like double, except that a Double can be null, whereas a double can't. In effect, this should make no difference to your code, except that you may want to add some error handling to deal with the case where window.apply(phase) evaluates to null.
I'm not sure how to write an equation in Netbeans.
The equation is supposed to be: (5−x)^2 +(5−y)^2 all under a square root.
This is what I have tried:
public static int getScore(int x, int y){
return ( (((5-x)^2 + (5-y)^2))^(1/2) );
This is one of those cases where there's a specialized library function:
return Math.hypot(5-x, 5-y);
This avoids the overflow and underflow issues in computing the square root of the sum of squares directly
The carat ^ performs exclusive or operator in java, which is a bits thing. Don't use it for exponents.
The expression you are looking for is
return Math.sqrt(Math.pow(5 - x, 2) + Math.pow(5 - y, 2)));
I'm trying to sort a collection of x and y points with an offset on x such that p.x-q.x should be treated equal IF p.x==q.x OR ABS(p.x-q.x) < offset.
Note that I'm taking the absolute value here, so I shouldn't be getting any negative values. My comparator is below:
private static class XYOrder implements Comparator<ExtractPojo> {
public int compare(ExtractPojo p, ExtractPojo q) {
Integer a=p.x.intValue();
Integer b=q.x.intValue();
Integer c=p.y.intValue();
Integer d=q.y.intValue();
int offset=Math.abs(a-b); //calculate offset from x
if(offset < 15 || a == b) //if x is the same, sort by y coordinate
return c-d;
else return a-b; //if x is not same sort by x coordinate
}
}
This code works for some cases, but I get the following error message on others:
Exception in thread "main" java.lang.IllegalArgumentException: Comparison method violates its general contract!
at java.util.TimSort.mergeHi(TimSort.java:868)
at java.util.TimSort.mergeAt(TimSort.java:485)
at java.util.TimSort.mergeForceCollapse(TimSort.java:426)
at java.util.TimSort.sort(TimSort.java:223)
at java.util.TimSort.sort(TimSort.java:173)
at java.util.Arrays.sort(Arrays.java:659)
at java.util.Collections.sort(Collections.java:217)
I have a feeling I'm violating a transivity rule as I've searched extensively through this site for an answer, but I'm not exactly sure how to test what I'm missing here.
I've tested this code without the offset and I don't get this error message, so I know it has to do with how I'm implementing the offset. I've Been trying to solve this for a few weeks with no luck.
I was hoping to get some tips or suggestions on this. Thank you very much.
So the only fix I can think of is first sorting by x position, then going through each x and adjusting the x's to be the same based on the offset, then doing the sort again by the x,y mentioned above without the offset. Just seems like a hack to do it that way, but I've never used a comparator before and I'm having difficulty solving this issue.
I have a feeling I'm violating a transivity rule
Indeed you are. Under your comparator, we have (0, 20) > (10, 10) > (20, 0) > (0, 20). (Also, it's spelled "transitivity".)
Generally, compare, compareTo, and equals methods shouldn't use tolerances, because tolerances are inherently intransitive. Two differences that both fall beneath a tolerance may add up to a difference above the tolerance.
Check your code again. This is what the Java docs have to say regarding the implementation of the compare() method.
The ordering imposed by a comparator c on a set of elements S is said to be consistent with equals if and only if c.compare(e1, e2)==0 has the same boolean value as e1.equals(e2) for every e1 and e2 in S.
Did you override the equals() method for your ExtractPojo class? You can find the doc here.
Also, you shouldn't be using code like a == b. Here, you have variables of type Integer. As such, it will only be checking whether the 2 variables point to the same object (which could be false in this case. More on that here). Use a.equals(b) instead.
So I did a few more tests and I believe found your issue: Overflows.
I made your compare method very simple and I was still getting that error:
public int compare(ExtractPojo p, ExtractPojo q) {
Integer x1 = p.x.intValue();
Integer x2 = q.x.intValue();
return x1 - x2;
}
This is because in some situations x1 - x2 will cause an overflow violating transitivity. To check for this do something like:
public int compare(ExtractPojo p, ExtractPojo q) {
Integer x1 = p.x.intValue();
Integer x2 = q.x.intValue();
checkSubtractionOverflow(x1, x2);
return x1 - x2;
}
//This will throw an exception if there is an overflow
public static void checkSubtractionOverflow(int left, int right) {
Math.subtractExact(left, right);
}
If you see the exception:
Exception in thread "main" java.lang.ArithmeticException: integer overflow
at java.lang.Math.subtractExact(Unknown Source)
Then you know you have overflow issues which will need to be addressed.
Basically, your code is saying this:
If the x coordinates are within 15 units of each other, use the y coordinates for comparison.
If the x coordinates are 15 or more units from each other, use the x coordinates for comparison
The x coordinates are equal case can go to either side without affecting the issue at hand.
I suspect the transitivity issue is going to be hit, for example, when:
P.x is within 15 units of Q.x and P < Q (because P.y < Q.y)
Q.x is within 15 units of R.x and Q < R (because Q.y < R.y)
AND P.x is beyond 15 units from R.x and P > R (because P.x > R.x)
Also, you are doing some unnecessary boxing/unboxing with the .intValue() calls. Integer a = P.x is an Integer to Integer assignment.
I'm not sure what's going on here but here's a section I'm having problems with (there's a few others but I think if I can figure out the logic here I can apply it elsewhere).
I recently had a problem where I was using point but couldn't get decimals so, as suggested, I switched to point2D to allow for doubles. Since switching I have been getting errors that I can't seem to understand how to fix because I don't see the cause (I know changing to point2D triggered it but I can't see the connection).
I have the following code:
Double x_data = (Double) data.get(k);
for (int c = 0; c <= 100; c++) { //the c variable caps the percent
double percent = roundTwoDecimals(c*.01);
double value1 =(sum - percent * x_data);
data is a list of point2D(which I'm casting to to double and sum is a variable I send in to this method that is really an integer but I cast it as a double. In eclipse I get the dreaded red underline under 'percent * x_data'. I googled and saw this error is often caused by someone trying to multiply a string or something but I'm fairly certain these all doubles. I get the following error now:
Exception in thread "main" java.lang.Error: Unresolved compilation problems:
The operator * is undefined for the argument type(s) double, Point2D.Double
The operator * is undefined for the argument type(s) double, Point2D.Double
Syntax error, insert ")" to complete ArgumentList
The operator * is undefined for the argument type(s) double, Point2D.Double
As far as I can tell everything involved in this process is either double or casted to double so I'm not sure why Point2D is involved in these operators.
Also I had a method that limited decimal places:
static double roundTwoDecimals(double d) {
DecimalFormat twoDForm = new DecimalFormat("#.###");
return Double.valueOf(twoDForm.format(d));
but Double.valueOf is not one of the options anymore so I got errors (Point2D errors) on that(to get around it, I just return d back right now without limiting the decimals).
I don't think there is a problem with point2D or anything but I must be structurally doing something wrong.
According to the stack trace, x_data is of type Point2D.Double, not java.lang.Double.
Check your imports, remove Point2D.Double and add java.lang.Double.
Now you won't be able to cast a Point2D to a Double. You probably mean to use yourDoublePoint2D.getX() adn yourDoublePoint2D.getY() which return doubles (no cast required).
As a side note, you can write something like this:
Double d1 = 1.5;
double d2 = 2.3;
double d3 = d1 * d2;
EDIT
You are likely importing Point2D.Double class with this:
import java.awt.geom.Point2D.*;
or
import java.awt.geom.Point2D.Double;
That creates a name collision with java.lang.Double. See below an example of code that would work as you expect:
import java.awt.geom.Point2D; //Note: only import Point2D, not Point2D.Double
public class Test {
public static void main(String[] args) {
Point2D.Double point = new Point2D.Double(1.5, 2.5);
double x = point.getX(); //1.5
double y = point.getY(); //2.5
Double xx = point.getX(); //1.5
Double yy = point.getY(); //2.5
}
}
If you don't import Point2D.Double, but refer to all instances of it by the full package name, an "unadorned" Double should be java.lang.Double.