我使用GenerateSolidThetaZero函数生成只包含整数组件的点列表。我的目标是使用弧度角度θ旋转这些离散点,旋转后的新点仍然应该包含整数分量。问题是我不希望任何两个点映射到相同的值。我想在旋转之前和之后获得相同数量的独特点。我使用round函数来解决这个问题,但我仍然会得到一些非唯一的映射。基本上我只是想找到一种方法来旋转这些点并保留尽可能多的结构(尽可能少地丢失点数)。我愿意使用任何图书馆。任何帮助或指导都会很棒。
注意:在我的代码中,半径为2,生成了13个点。在Pi / 6旋转后,由于这些点映射到另一个已经映射到的点的相同值,我最终失去了4个点。
public class pointcheck{
// this HashSet will be used to check if a point is already in the rotated list
public static HashSet<Point> pointSet = new HashSet<Point>();
public static void main(String args[]) {
//generates sort of circular solid with param being the radius
ArrayList<Point> solid_pointList = GenerateSolidThetaZero(2);
//used to store original point as first part of pair and rotated point as second part of pair
ArrayList<Pair> point_pair = new ArrayList<Pair>();
//goes through all points in Solid_pointList adds each point to Point List with its corresponding rotated angle
for(Point t : solid_pointList){
point_pair.add(new Pair(t,rotation_about_origin(t,Math.PI / 6)));
}
for(Pair t : point_pair){
System.out.println(t.getFirst() + " " + t.getSecond());
}
System.out.println(pointSet.size());
}
//takes the point we want to rotate and then the angle to rotate it by
public static Point rotation_about_origin(Point P, double theta){
Point new_P = null;
double old_X = P.x;
double old_Y = P.y;
double cos_theta = Math.cos(theta);
double sin_theta = Math.sin(theta);
double new_X = old_X * cos_theta - old_Y * sin_theta;
double new_Y = old_X * sin_theta + old_Y * cos_theta;
new_P = new Point((int)Math.round(new_X),(int)Math.round(new_Y));
//if new_p is already in rotated solid
if(pointSet.contains(new_P))
System.out.println("Conflict " + P + " " + new_P);
else
//add new_P to pointSet so we know a point already rotated to that spot
pointSet.add(new_P);
return new_P;
}
private static ArrayList<Point> GenerateSolidThetaZero(int r){
int rsq = r * r;
ArrayList<Point> solidList=new ArrayList<Point>();
for (int x=-r;x<=r;x++)
for (int y=-r;y<=r;y++)
if (x*x + y*y <= rsq)
solidList.add(new Point(x,y));
return solidList;
}
public static class Pair<F,S>{
private F first; //first member of pair
private S second; //second member of pair
public Pair(F first, S second) {
this.first = first;
this.second = second;
}
public void setFirst(F first) {
this.first = first;
}
public void setSecond(S second) {
this.second = second;
}
public F getFirst() {
return first;
}
public S getSecond() {
return second;
}
}
}//end of pointcheck class
如何使用不使用90的整数倍的角度旋转点?如果已经采用了映射,我应该在旋转后转换点?
答案 0 :(得分:0)
旋转的磁盘将覆盖与原始磁盘完全相同的像素。因此,您实际上想要解决从原始像素到旋转像素的分配问题。
将原始像素(ox, oy)
指定给对应像素(cx, cy)
的成本可以用电位表示。例如,距离:
E_o,c = length(R(ox, oy, theta) - (cx, cy))
,其中R
是旋转运算符。或者,您也可以尝试其他规范,例如二次距离。
然后,问题是找到最小化整体能量的对应关系:
min_C Sum_{o \in O} E_o,c
完全解决这个问题的算法是Hungarian Algorithm。但是,如果你有大量的像素,这是非常昂贵的。
相反,这是一个近似的概念:
在目标像素中,还存储旋转位置,而不是仅具有颜色。然后,像以前一样顺序旋转原始像素。围绕旋转位置并检查相应像素是否仍然被占用。
如果没有,请将旋转(未接地)位置与新颜色一起存储。
如果它已被占用,请检查如果您交换了对应关系,能量是否会减少。如果是这样,交换它们,这将留下前一个像素。在任何情况下,您都有一个未映射的原始像素。将此像素存储在列表中。
完成此过程后,您将获得部分对应关系图和未映射像素列表。选择任何未映射的像素。分析目标像素的邻居。可能总会有一个未占用的像素(虽然我没有证明)。如果是这样,请选择此项。如果没有,请检查所有相邻像素以获得最佳能量减少和交换。继续,直到列表为空。
近似算法只是一个想法,我没有证据证明它实际上是可行的。但听起来好像值得一试。它肯定会比匈牙利算法更快。但是,这种近似只适用于具有p> = 1的Lp范数,用于潜在的定义。