美文网首页
移动图形边,求移动线与另外两条相交线的新交点坐标算法实现

移动图形边,求移动线与另外两条相交线的新交点坐标算法实现

作者: 墨色尘埃 | 来源:发表于2017-07-27 15:46 被阅读0次

移动图形的一条线增大或缩小图形,但是保持形状不变,求移动后移动线与另外两条相交线的新交点(或者说图形的新坐标)。如图所示:将直线①移动到虚线②处,求虚线处的E、F两个新坐标。

思路:
已经AC点求出直线①的斜率,当①移动到②处时,直线②的斜率和①是相同的,同时可知②线上的一个已经点(即鼠标抬起时ACTION_UP事件中的点)这样就可以求出直线②的方程。直线③和④方程分别由BC和AB求得,求新的相交点让方程相等即可。
注:
这里的斜率是按照数学中的第一象限求得的,但是在Android中整个屏幕所处的象限与数学中是不一样的,整个屏幕以左上角为(0,0)点向右X增大向下Y增大,但是并不影响求得直线方程求出相交点。

TIM截图20170727151205.png
 /**
     * 计算直线斜率
     */
    public static float calSlope(Point point, Point point1) {
        float k = (point1.getY() - point.getY()) / (point1.getX() - point.getX());
        return k;
    }

    /**
     * 根据 不同直线上的两个点 求两条直线的相交点x坐标
     * @param moveLineK 移动线斜率
     * @param crossLineK 相交线斜率
     * @param movePoint 移动线抬起时鼠标点坐标
     * @param inwardPoint 相交线的两个坐标中任意一个
     * @return
     */
    public static float calCrosspointX(float moveLineK, float crossLineK, Point movePoint, Point inwardPoint) {
        float x, temp;
        float movePointX = movePoint.getX();
        float movePointY = movePoint.getY();
        float inwardPointX = inwardPoint.getX();
        float inwardPointY = inwardPoint.getY();

        temp = moveLineK * movePointX - crossLineK * inwardPointX + inwardPointY - movePointY;
        x = temp / (moveLineK - crossLineK);
        return x;
    }

    /**
     * 根据相交点x坐标求已经方程经过该点的y坐标
     */
    public static float calBeelineEquation(float k, float x, Point point) {
        float y;
        y = k * (x - point.getX()) + point.getY();
        return y;
    }
public class FirstActivity extends AppCompatActivity implements View.OnClickListener {

    private DrawPolygonView2 drawPloygonView2;
    private Button clear;
    private TextView textView;
    private List<Point> list;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_first);
        drawPloygonView2 = (DrawPolygonView2) findViewById(R.id.drawPloygonView2);
        clear = (Button) findViewById(R.id.clear);
        textView = (TextView) findViewById(R.id.textView);

        clear.setOnClickListener(this);

        setOrderPointList();
        Point movePoint = new Point(0, 1);  //移动线抬起时的鼠标的点坐标
//        Point movePoint = new Point(6, 7);  //移动线抬起时的鼠标的点坐标
        getPoint(list, movePoint);


    }


    /**
     * 该集合点必须是顺序的 (顺时针),
     * 第0个为移动线的坐标
     * 第1个为移动线的坐标
     * 第2个为第一条相交线另一个坐标
     * 第3个为第二条相交线另一个坐标
     */
    public void setOrderPointList() {
        list = new ArrayList<>();  //顺时针添加
//        Point point = new Point(5, 6);  //移动线的坐标 :集合中第0个
//        Point point1 = new Point(8, 7);  //移动线的坐标
//        Point point2 = new Point(10, 0);  //第一条相交线另一个坐标
//        Point point3 = new Point(2, 1);  //第二条相交线另一个坐标
//        list.add(point);
//        list.add(point1);
//        list.add(point2);
//        list.add(point3);

        Point point = new Point(0, 0);  //移动线的坐标 :集合中第0个
        Point point1 = new Point(2, 2);  //移动线的坐标
        Point point2 = new Point(1, 0);  //第一条相交线另一个坐标
        Point point3 = new Point(1, 0);  //第二条相交线另一个坐标
        list.add(point);
        list.add(point1);
        list.add(point2);
        list.add(point3);
    }

    public List<Point> getPoint(List<Point> list, Point movePoint) {

        List<Point> moveinwardPoint = new ArrayList<>();
        float moveLineK = DrawUtils.calSlope(list.get(0), list.get(1)); //移动线的斜率
        float crossLineK = DrawUtils.calSlope(list.get(1), list.get(2)); //与移动线相交的其他两条线的斜率

        float crosspointX = DrawUtils.calCrosspointX(moveLineK, crossLineK, movePoint, list.get(1));
        float crosspointY = DrawUtils.calBeelineEquation(moveLineK, crosspointX, movePoint);

        float crossLineK1 = DrawUtils.calSlope(list.get(0), list.get(3));  //与移动线相交的其他两条线的斜率
        float crosspointX1 = DrawUtils.calCrosspointX(moveLineK, crossLineK1, movePoint, list.get(3));
        float crosspointY1 = DrawUtils.calBeelineEquation(moveLineK, crosspointX1, movePoint);


        Log.e("FirstActivity", "moveLineK:" + moveLineK + "/" + "crossLineK:" + crossLineK + "/" +
                "crosspointX:" + crosspointX + "/" + "crosspointY:" + crosspointY);
        Log.e("FirstActivity", "moveLineK:" + moveLineK + "/" + "crossLineK1:" + crossLineK1 + "/" +
                "crosspointX1:" + crosspointX1 + "/" + "crosspointY1:" + crosspointY1);

        moveinwardPoint.add(new Point(crosspointX, crosspointY));
        moveinwardPoint.add(new Point(crosspointX1, crosspointY1));
        return moveinwardPoint;

    }


    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.clear:
                drawPloygonView2.cleanDraw();
                break;
            default:
                break;
        }

    }
}

另附一份自定义View中关于计算方便的常用方法

public class DrawUtils {

    /**
     * 判断点击的点是否在图形内
     */
    static Region re = new Region();

    public static boolean isInside(Path path, MotionEvent event) {
        //构造一个区域对象,左闭右开的。
        RectF r = new RectF();
        //计算控制点的边界
        path.computeBounds(r, true);
        //设置区域路径和剪辑描述的区域
        re.setPath(path, new Region((int) r.left, (int) r.top, (int) r.right, (int) r.bottom));
        //在封闭的path内返回true 不在返回false
        return re.contains((int) event.getX(), (int) event.getY());
    }

    /**
     * 标点是否落在指定的多边形区域内
     * 判断坐
     */
    public static int PtInRegion(Point p0, List<Point> plg) {
        int nowValue, lastValue, dValue, sumValue = 0;
        double tempMult;
        double eps = 0.0000000000000001;
        Point l1, l2;

        if (plg.get(0).getY() > p0.getY()) {
            lastValue = 1;
        } else if (plg.get(0).getY() < p0.getY()) {
            lastValue = -1;
        } else {
            lastValue = 0;
        }

        for (int i = 1; i < plg.size(); i++) {
            //计算矢量积
            l1 = plg.get(i - 1);
            l2 = plg.get(i);
            tempMult = xmult(l1, l2, p0);

            //判断点是否在边上
            if (Math.abs(tempMult) < eps && (l1.getX() - p0.getX()) * (l2.getX() - p0.getX()) < eps && (l1.getY() -
                    p0.getY()) * (l2.getY() - p0.getY()) < eps) {
                return 0;
            }

            //判断是否跨射线
            if (l2.getY() > p0.getY()) {
                nowValue = 1;
            } else if (l2.getY() < p0.getY()) {
                nowValue = -1;
            } else {
                nowValue = 0;
            }

            dValue = nowValue - lastValue;

            //判断是否与射线相交,相交则累加
            if (dValue != 0) {
                if (dValue > 0 && tempMult > 0) {
                    sumValue += dValue;
                } else if (dValue < 0 && tempMult < 0) {
                    sumValue += dValue;
                }
            }

            lastValue = nowValue;
        }

        //判断最终结果,如和为0,则在多边形外,否则在多边形内
        if (sumValue == 0) {
            return -1;
        } else {
            return 1;
        }
    }

    public static double xmult(Point p1, Point p2, Point p0) {
        return (p1.getX() - p0.getX()) * (p2.getY() - p0.getY()) - (p2.getX() - p0.getX()) * (p1.getY() - p0.getY());
    }


    /**
     * 根据手机的分辨率从 dp 的单位 转成为 px(像素)
     */
    public static int dip2px(Context context, float dpValue) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (dpValue * scale + 0.5f);
    }

    /**
     * 根据手机的分辨率从 px(像素) 的单位 转成为 dp
     */
    public static int px2dip(Context context, float pxValue) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (pxValue / scale + 0.5f);
    }

    /**
     * @param str 字符是否为空
     */
    public static boolean isEmpty(String str) {
        if (null == str || str.trim().length() == 0
                || str.trim().equals("null")) {
            return true;
        }
        return false;
    }

    /**
     * 保留指定位数
     *
     * @param num 保留位数
     */
    public static String formatString(Object obj, int num) {
        try {
            BigDecimal bd = new BigDecimal(obj + "");
            bd = bd.setScale(num, BigDecimal.ROUND_DOWN);
            return bd.toString();
        } catch (Exception e) {
            return obj.toString();
        }
    }

    /**
     * 获取屏幕宽高
     *
     * @return size[0]:width size[1]:height
     */
    public static int[] getScreenSize(Context context) {
        int[] size = new int[2];
        DisplayMetrics dm = new DisplayMetrics();
        WindowManager mg = (WindowManager) context
                .getSystemService(Context.WINDOW_SERVICE);
        mg.getDefaultDisplay().getMetrics(dm);
        size[0] = dm.widthPixels;
        size[1] = dm.heightPixels;
        return size;
    }

    /**
     * 获取控件左上角和右下角的点
     */
    public static Point[] getPointWithView(View v) {
        Point[] coordinate = new Point[2];
        int left = v.getLeft();
        int top = v.getTop();
        int right = v.getRight();
        int bottom = v.getBottom();
        Point lt = new Point(left, top);
        Point rb = new Point(right, bottom);
        coordinate[0] = lt;
        coordinate[1] = rb;
        return coordinate;
    }

    // 点到直线的距离 : 点(x0,y0) 到由两点组成的线段(x1,y1) ,( x2,y2 )
    public static double pointToLine(float x0, float y0, Point point1, Point point2) {
        float x1 = point1.getX();
        float y1 = point1.getY();
        float x2 = point2.getX();
        float y2 = point2.getY();
        double space = 0;
        double a, b, c;
        a = lineSpace(x1, y1, x2, y2);// 线段的长度
        b = lineSpace(x1, y1, x0, y0);// (x1,y1)到点的距离
        c = lineSpace(x2, y2, x0, y0);// (x2,y2)到点的距离
        if (c <= 0.000001 || b <= 0.000001) {
            space = 0;
            return space;
        }
        if (a <= 0.000001) {
            space = b;
            return space;
        }
        if (c * c >= a * a + b * b) {
            space = b;
            return space;
        }
        if (b * b >= a * a + c * c) {
            space = c;
            return space;
        }
        double p = (a + b + c) / 2;// 半周长
        double s = Math.sqrt(p * (p - a) * (p - b) * (p - c));// 海伦公式求面积
        space = 2 * s / a;// 返回点到线的距离(利用三角形面积公式求高)
        return space;
    }

    // 计算两点之间的距离
    public static double lineSpace(float x1, float y1, float x2, float y2) {
        double lineLength = 0;
        lineLength = Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2)
                * (y1 - y2));
        return lineLength;
    }

    /**
     * 计算两点间距离
     */
    public static float calTwoPointDistance(Point first, Point second) {
        float firstX = first.getX();
        float firstY = first.getY();

        float secondX = second.getX();
        float secondY = second.getY();
        float lineDis = (float) Math.sqrt(Math.pow(secondX - firstX, 2) + Math.pow(secondY - firstY, 2));
        return lineDis;
    }


    /**
     * 计算直线斜率
     */
    public static float calSlope(Point point, Point point1) {
        float k = (point1.getY() - point.getY()) / (point1.getX() - point.getX());
        return k;
    }

    /**
     * 根据 不同直线上的两个点 求两条直线的相交点x坐标
     * @param moveLineK 移动线斜率
     * @param crossLineK 相交线斜率
     * @param movePoint 移动线抬起时鼠标点坐标
     * @param inwardPoint 相交线的两个坐标中任意一个
     * @return
     */
    public static float calCrosspointX(float moveLineK, float crossLineK, Point movePoint, Point inwardPoint) {
        float x, temp;
        float movePointX = movePoint.getX();
        float movePointY = movePoint.getY();
        float inwardPointX = inwardPoint.getX();
        float inwardPointY = inwardPoint.getY();

        temp = moveLineK * movePointX - crossLineK * inwardPointX + inwardPointY - movePointY;
        x = temp / (moveLineK - crossLineK);
        return x;
    }

    /**
     * 根据相交点x坐标求已经方程经过该点的y坐标
     */
    public static float calBeelineEquation(float k, float x, Point point) {
        float y;
        y = k * (x - point.getX()) + point.getY();
        return y;
    }
}

相关文章

  • 移动图形边,求移动线与另外两条相交线的新交点坐标算法实现

    移动图形的一条线增大或缩小图形,但是保持形状不变,求移动后移动线与另外两条相交线的新交点(或者说图形的新坐标)。如...

  • 均线进化之路

    双均线策略,通过建立m天移动平均线,n天移动平均线,则两条均线必有交点。若m>n,n天平均线“上穿越”m天均线则为...

  • iOS Swift 计算两点与直线之间的相交点

    图中的X Y 坐标系的点连成的线与白色K线 形成的三角形 求斜线与三角形的相交点坐标 解:我们先计算出最大直角三...

  • 直线相交产生的角:对顶角

    欢迎关注公z号:沈阳奥数 若两条直线只有一个公共交点,称这两条直线为相交线。不相交的两条直线角做平行线。 两条直线...

  • 我能想到最浪漫的事……

    忽然觉得男女之间的相处就好比两条可能相交的直线,缘分使两条平行线产生交点,而支持两线合一的则是相互之间的追逐与礼让...

  • 我们

    我们两条相交线然而我们注定有个交点并且是个限时交点我们是天地间的过客很多人事都会有无形的东西左右我们的决定相交线也...

  • 一别两宽,各生欢喜

    都说男女像两条直线,有的是平行线,有的则是相交线。有人说我跟她(他)就像两条平行线永远没有交点多么悲哀,但是有...

  • 2022-10-29 齐次坐标与透视

    一、齐次坐标 问题:两条平行线可以相交?在欧氏空间(几何学)中,同一平面上的两条平行线不能相交,或者说不能永远相交...

  • 移动平均线”操作的简单演示(My语言版)

    双移动平均线策略,通过建立m日和n日移动平均线,这两条移动平均线在价格移动期间必须有交叉点。如果是m>n ,则n日...

  • 跟诸子学游戏 避障算法

    避障算法最主要的思想是, 在移动物体中心点与当前障碍物之间画一条线,称为A线 再做一条垂直于 物体与障碍物相交的一...

网友评论

      本文标题:移动图形边,求移动线与另外两条相交线的新交点坐标算法实现

      本文链接:https://www.haomeiwen.com/subject/ubmzkxtx.html