我有一个课程,负责管理从屏幕坐标到图像坐标的转换 但是,我有一个"关闭一个错误"。
以下给出318,198,而不是319,199:
@Test
public void test6rightScreenCornerToImageCoOrdAfterZoomingAndScaling() {
PointTranslation pointTranslation = new PointTranslation();
pointTranslation.setOriginalSize(0, 0, 320, 200); // original image
pointTranslation.zoomIn(9, 9, 310, 190); // zoomed image starting at 9,9
pointTranslation.scale(0, 0, 800, 800);
Point translatedPoint = pointTranslation.transformPoint(799,799);
System.out.println(testName.getMethodName() + " : " + translatedPoint.toString());
assertTrue(translatedPoint.x == 319);
assertTrue(translatedPoint.y == 199);
}
=============================================== ==============
完整清单:
package gtx;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.internal.gdip.PointF;
import org.eclipse.swt.internal.gdip.RectF;
@SuppressWarnings("restriction")
public class PointTranslation {
RectF originalSize = null;
RectF currentSize = null;
RectF scaledSize = null;
public void setOriginalSize(int originX, int originY, int width, int height) {
originalSize = getRectangle(originX, originY, width, height);
currentSize = originalSize;
}
public void zoomIn(int originX, int originY, int width, int height) {
// System.out.println("addTranslation: " + originX + " " + originY + " "
// + width + " " + height);
currentSize = getRectangle(originX, originY, width, height);
}
public void scale(int originX, int originY, int width, int height) {
// System.out.println("addTranslation: " + originX + " " + originY + " "
// + width + " " + height);
scaledSize = getRectangle(originX, originY, width, height);
}
public boolean isPointWithinBounds(Point point) {
return isPointWithinBounds(point.x, point.y);
}
public boolean isPointWithinBounds(int xPos, int yPos) {
boolean ret = false;
if (scaledSize != null) {
RectF sourceRec = scaledSize;
int xBounds = (int) (sourceRec.Width + sourceRec.X);
int yBounds = (int) (sourceRec.Height + sourceRec.Y);
ret = (xPos < xBounds) && (yPos < yBounds) && (xPos > sourceRec.X) && (yPos > sourceRec.Y);
}
return ret;
}
public Point transformPoint(Point point) {
return transformPoint(point.x, point.y);
}
public Point transformPoint(int xPos, int yPos) {
Point sourcePoint = new Point((int) xPos, (int) yPos);
Point retPoint = sourcePoint;
if (this.scaledSize != null) {
retPoint = transformPoint(this.scaledSize, this.currentSize, sourcePoint);
}
return retPoint;
}
/*
* Rectangle 1 has (x1, y1) origin and (w1, h1) for width and height, and
* Rectangle 2 has (x2, y2) origin and (w2, h2) for width and height, then
*
* Given point (x, y) in terms of Rectangle 1 co-ords, to convert it to
* Rectangle 2 co-ords: xNew = ((x-x1)/w1)*w2 + x2; yNew = ((y-y1)/h1)*h2 +
* y2;
*/
private Point transformPoint(RectF source, RectF destination, Point intPoint) {
PointF point = new PointF();
point.X = intPoint.x;
point.Y = intPoint.y;
return transformPoint(source, destination, point);
}
private Point transformPoint(RectF source, RectF destination, PointF point) {
return new Point((int) ((((point.X - source.X) / source.Width) * destination.Width + destination.X)),
(int) ((((point.Y - source.Y) / source.Height) * destination.Height + destination.Y)));
}
private RectF getRectangle(int x, int y, int width, int height) {
RectF rect = new RectF();
rect.X = x;
rect.Y = y;
rect.Height = height;
rect.Width = width;
return rect;
}
private PointF getPoint(int x, int y) {
PointF retPoint = new PointF();
retPoint.X = x;
retPoint.Y = y;
return retPoint;
}
public void reset() {
this.originalSize = null;
this.currentSize = null;
this.scaledSize = null;
}
}
我的问题似乎与四舍五入有关。奇怪的是,对于一些测试用例我需要Round Up来获得正确的Point,有时我需要向上舍入。我遗漏了像缩放因子之类的东西。有关如何正确翻译两个矩形之间的任何建议吗?
我尝试了以下方法,但仍然没有快乐:
private Point transformPoint(RectF source, RectF destination, PointF point) {
float xPercent = normalize(point.X,source.X,source.Width);
float destX = xPercent*(Math.abs(destination.Width - destination.X)) + destination.X;
float yPercent = normalize(point.Y,source.Y,source.Height);
float destY = yPercent*(Math.abs(destination.Height - destination.Y)) + destination.Y;
System.out.println("Float x,y: " + destX + ", " + destY);
System.out.println("Ceil Float x,y: " + Math.floor(destX) + ", " + Math.floor(destY) );
return new Point((int)Math.floor(destX), (int)Math.floor(destY));
}
private float normalize(float value, float min, float max) {
return Math.abs((value - min) / (max - min));
}
答案 0 :(得分:2)
In running the test case and stepping through the code, my debugging shows the following substitutions...
transformPoint(RectF source, RectF destination, PointF point) {
return new Point (
(int) (((( 799 - 0 ) / 800 ) * 310 ) + 9 )),
(int) (((( 799 - 0 ) / 800 ) * 190 ) + 9 ))
);
}
The first half of the equation returns 318.6125
. The second half of the equation returns 198.7625
.
You need to either
int
transformation truncates to the
desired value (such as + 1
at the end) int
And as Mathew noted, multiple translations in a row distort and magnify the problem, much like averaging averages.
答案 1 :(得分:1)
如Reenactor所述,您需要在转换为int之前对点进行舍入:
private Point transformPoint(RectF source, RectF destination, PointF point) {
final int ptx = Math.round((((point.X - source.X) / source.Width) * destination.Width + destination.X));
final int pty = Math.round((((point.Y - source.Y) / source.Height) * destination.Height + destination.Y));
return new Point(ptx, pty);
}
答案 2 :(得分:0)
Is it possible you are converting the interim results after each translation to integer points?
Remember, org.eclipse.swt.graphics.Point
stores x
and y
as int
, so any fractions in your calculations are dropped.
That is:
1) First translation:
x1 = ((799 - 0) / 800) * 301 + 9 = 309.62375
y1 = ((799 - 0) / 800) * 181 + 9 = 189.77375
If you were storing those in a Point
object before going into the next translation, they would be truncated to (309, 189) and you would get
2) Second translation
x2 = ((309 - 9) / 301) * 320 + 0 = 318.93...
y2 = ((189 - 9) / 181) * 200 + 0 = 198.89...
Which would, in turn, be truncated to (318, 198).