java判断某个点是否在所画范围内(多边形/圆形)

本文介绍了一种用于判断二维平面上的点是否位于特定多边形或圆形内部的算法。通过计算与多边形边界的交点数量来判断点的位置,并提供了点与圆形位置关系的判断方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

测试类

/** 
 * java判断某个点是否在所画范围内(多边形【isPtInPoly】/圆形【distencePC】) 
 * @param point 检测点 
 * @param pts   多边形的顶点 
 * @return      点在多边形内返回true,否则返回false 
 * @author         ardo
 */ 
public class IsPtInPoly {
    
    /** 
     * 判断点是否在多边形内 
     * @param point 检测点 
     * @param pts   多边形的顶点 
     * @return      点在多边形内返回true,否则返回false 
     */  
    public static boolean isPtInPoly(Point2D point, List<Point2D> pts){  
          
        int N = pts.size();  
        boolean boundOrVertex = true; //如果点位于多边形的顶点或边上,也算做点在多边形内,直接返回true  
        int intersectCount = 0;//cross points count of x   
        double precision = 2e-10; //浮点类型计算时候与0比较时候的容差  
        Point2D p1, p2;//neighbour bound vertices  
        Point2D p = point; //当前点  
          
        p1 = pts.get(0);//left vertex          
        for(int i = 1; i <= N; ++i){//check all rays              
            if(p.equals(p1)){  
                return boundOrVertex;//p is an vertex  
            }  
              
            p2 = pts.get(i % N);//right vertex              
            if(p.x < Math.min(p1.x, p2.x) || p.x > Math.max(p1.x, p2.x)){//ray is outside of our interests                  
                p1 = p2;   
                continue;//next ray left point  
            }  
              
            if(p.x > Math.min(p1.x, p2.x) && p.x < Math.max(p1.x, p2.x)){//ray is crossing over by the algorithm (common part of)  
                if(p.y <= Math.max(p1.y, p2.y)){//x is before of ray                      
                    if(p1.x == p2.x && p.y >= Math.min(p1.y, p2.y)){//overlies on a horizontal ray  
                        return boundOrVertex;  
                    }  
                      
                    if(p1.y == p2.y){//ray is vertical                          
                        if(p1.y == p.y){//overlies on a vertical ray  
                            return boundOrVertex;  
                        }else{//before ray  
                            ++intersectCount;  
                        }   
                    }else{//cross point on the left side                          
                        double xinters = (p.x - p1.x) * (p2.y - p1.y) / (p2.x - p1.x) + p1.y;//cross point of y                          
                        if(Math.abs(p.y - xinters) < precision){//overlies on a ray  
                            return boundOrVertex;  
                        }  
                          
                        if(p.y < xinters){//before ray  
                            ++intersectCount;  
                        }   
                    }  
                }  
            }else{//special case when ray is crossing through the vertex                  
                if(p.x == p2.x && p.y <= p2.y){//p crossing over p2                      
                    Point2D p3 = pts.get((i+1) % N); //next vertex                      
                    if(p.x >= Math.min(p1.x, p3.x) && p.x <= Math.max(p1.x, p3.x)){//p.x lies between p1.x & p3.x  
                        ++intersectCount;  
                    }else{  
                        intersectCount += 2;  
                    }  
                }  
            }              
            p1 = p2;//next ray left point  
        }  
          
        if(intersectCount % 2 == 0){//偶数在多边形外  
            return false;  
        } else { //奇数在多边形内  
            return true;  
        }  
          
    } 
    
    /**
     * 判断是否在圆形内
     * @param p
     * @param c
     * @return
     */
    public static String distencePC(Point2D p,Circle c){//判断点与圆心之间的距离和圆半径的关系
        String s ;
        double d2 = Math.hypot( (p.getX() - c.getCC().getX() ), (p.getY() - c.getCC().getY()) );
        System.out.println("d2=="+d2);
        double r = c.getR();
        if(d2 > r){
              s = "圆外";
        }else if(d2 < r){
             s = "圆内";
        }else{
              s = "圆上";
        }
        return s;
    }
 
    
    
    
    public static void main(String[] args) {  
          
        Point2D point = new Point2D(116.404072, 39.916605);  
          
        // 测试一个点是否在多边形内  
        List<Point2D> pts = new ArrayList<Point2D>();  
        pts.add(new Point2D(116.395, 39.910));  
        pts.add(new Point2D(116.394, 39.914));  
        pts.add(new Point2D(116.403, 39.920));  
        pts.add(new Point2D(116.402, 39.914));  
        pts.add(new Point2D(116.410, 39.913));  
          
        if(isPtInPoly(point, pts)){  
            System.out.println("点在多边形内");  
        }else{  
            System.out.println("点在多边形外");  
        }  
        
        // 测试一个点是否在圆形内  
        Point2D centerPoint = new Point2D(116.404172, 39.916605);  
        Circle c = new Circle();
        c.setCC(centerPoint);
        c.setR(0.0056);
        String s = distencePC(point,c);
        System.out.println("点是否在圆内:"+s);
    } 
    
}
 

 

 

/**
 * 圆形类
 * @author ardo
 *
 */
public class Circle {
     private double r;
     private Point2D cc;
     
     public void setR(double a){
           r = a;
     }
     public void setCC(Point2D centerOfCir){
           cc = centerOfCir;
     }
     public double getR(){
           return r;
     }
     public Point2D getCC(){
           return cc;
     }
}
 

 

 

public class Point2D {
    
    public double x;
    public double y;
    
    public Point2D(double x, double y) {
        super();
        this.x = x;
        this.y = y;
    }
    
    public double getX() {
        return x;
    }
    public void setX(double x) {
        this.x = x;
    }
    public double getY() {
        return y;
    }
    public void setY(double y) {
        this.y = y;
    }
    
}

<think>我们要实现一个功能:在Java Swing中让游戏画面在指定的范围内变暗。这通常用于实现游戏中的“视野”效果,比如只照亮角色周围区域,其他地方变暗。 思路: 1. 我们可以使用一个全屏的半透明黑色遮罩层,然后在指定区域(比如圆形区域)清除遮罩,这样该区域就会变亮(因为遮罩被清除,所以能看到下面的画面),而其他区域则变暗。 2. 另一种方法是绘制一个全屏的黑色半透明图层,然后在指定区域绘制一个透明的“洞”。这样,只有洞的区域是亮的,其余区域是暗的。 这里我们采用第二种方法,因为更直观。 具体步骤: - 我们需要一个自定义的JPanel,并重写其paintComponent方法。 - 在paintComponent方法中,首先绘制游戏画面(作为背景),然后绘制一个全屏的半透明黑色矩形(作为遮罩)。 - 然后,我们在遮罩上“挖洞”:在指定区域(比如圆形)绘制一个透明的形状。我们可以使用Swing的XOR模式或者使用AlphaComposite来实现。但更简单的是使用一个径向渐变,从透明到黑色。不过,为了简单和效果,我们可以使用剪裁区域(clip)来排除一个圆形区域,然后绘制一个半透明的矩形,这样圆形区域就不会被绘制,从而形成亮区。但是这种方法可能不够灵活。 更直接的方法是使用AlphaComposite的CLEAR规则来清除指定区域的像素。但是注意,CLEAR规则会将RGBA都设置为0,也就是完全透明。但我们的遮罩是半透明的黑色,所以清除后,该区域就完全透明,从而显示下面的游戏画面,达到变亮的效果。 然而,使用CLEAR需要小心,因为它会清除所有内容,包括背景。所以我们可以这样: - 首先绘制游戏背景。 - 然后绘制一个全屏的半透明黑色矩形(作为遮罩)。 - 然后,我们设置一个组合规则(AlphaComposite)为CLEAR,并在指定区域(比如圆形)绘制一个形状,这样就会清除该区域的遮罩,从而露出背景。 但是,注意:清除操作会清除到背景,如果背景是游戏画面,那么清除后就会显示游戏画面。然而,我们是在遮罩层上清除,所以清除后,该区域就没有遮罩,从而显示下面的游戏画面。 但是,我们也可以使用另一种方法:使用一个径向渐变的圆形,从中心透明到边缘黑色。这样更自然,而且可以实现渐变效果。 这里我们提供两种实现: 方法1:使用清除模式(CLEAR)来挖洞 方法2:使用径向渐变绘制一个从透明到黑色的圆形 由于方法1可能不够平滑(没有渐变边缘),我们使用方法2实现一个带有渐变边缘的变暗效果。 步骤(方法2): 1. 在自定义的JPanel中,重写paintComponent方法。 2. 首先绘制游戏背景(假设游戏背景已经绘制好)。 3. 然后创建一个RadialGradientPaint,从圆心(指定位置)向外扩散,颜色从透明(0,0,0,0)到半透明黑色(0,0,0,0.7)或全黑(0,0,0,1.0)。 4. 使用这个RadialGradientPaint绘制一个覆盖整个面板的矩形(实际上,我们会绘制一个圆形区域,但为了覆盖整个面板,我们绘制一个矩形,而渐变会在圆形外变为黑色?)。实际上,RadialGradientPaint可以设置半径,然后我们绘制一个矩形,矩形中超出圆形半径的部分会显示黑色。 但是,注意:RadialGradientPaint只会在圆形区域内绘制渐变,圆形区域外我们可以用另一种颜色。但是,我们想要整个面板都覆盖黑色,只是圆形区域内是渐变的。我们可以这样设置:在圆形区域内,颜色从圆心透明到边缘黑色,而圆形区域外,我们想要纯黑色。这可以通过两个步骤实现,或者使用MultipleGradientPaint的循环模式?但是RadialGradientPaint不支持多个颜色之外的颜色。所以我们可以先绘制一个全屏的黑色,然后在上面绘制一个径向渐变的圆形(从透明到黑色),这样圆形区域内的黑色被渐变覆盖,而圆形区域外仍然是黑色。但是这样绘制的结果是:圆形区域内是渐变的,圆形区域外是纯黑。但我们希望整个屏幕都是半透明的黑色,只是圆形区域内是渐变的透明。 实际上,我们可以这样:我们想要的效果是,圆形区域内从圆心透明(0)到边缘半透明(0.7),圆形区域外都是半透明(0.7)。那么我们可以设置两个颜色:圆心处为透明(0,0,0,0),圆边缘处为半透明黑色(0,0,0,0.7)。然后设置RadialGradientPaint的循环模式为CLAMP,这样在圆边缘之外的颜色就都是圆边缘的颜色(即半透明黑色)。这样我们就得到了一个圆形区域内有渐变,而圆形区域外都是半透明黑色。 因此,我们可以在整个面板上绘制一个矩形,使用我们创建的RadialGradientPaint,这样就会在指定位置形成渐变。 代码步骤: 1. 创建RadialGradientPaint对象,需要指定圆心、半径、两个颜色(0f处为透明,1f处为半透明黑色)。 2. 设置Graphics2D的Paint为这个RadialGradientPaint。 3. 填充整个面板(矩形)。 注意:这样绘制后,整个面板都会被覆盖,但是圆形区域内是渐变的,圆形区域外是纯的半透明黑色(因为渐变在1f处是半透明黑色,而超出半径的部分使用CLAMP模式,所以也是半透明黑色)。 但是,我们想要的效果是圆形区域内变亮(即遮罩变淡),而圆形区域外是半透明黑色(遮罩存在)。所以这样绘制后,圆形区域内会从中心到边缘逐渐变暗,而圆形区域外是均匀的半透明黑色。 示例代码: 假设我们有一个JFrame,其中包含一个自定义的JPanel(比如叫做GamePanel)。在GamePanel中,我们重写paintComponent方法。 注意:为了演示,我们假设游戏背景是一张图片或者纯色。这里我们用绿色背景代替。 代码实现:</think># Java Swing实现指定区域变暗效果 在Java Swing中实现游戏画面在指定范围内变暗的效果,可以通过创建一个半透明的遮罩层并在特定区域"挖洞"来实现。下面是一个完整的实现方案: ```java import javax.swing.*; import java.awt.*; import java.awt.geom.Area; import java.awt.geom.Ellipse2D; import java.awt.geom.Rectangle2D; public class DarkenedGameView extends JFrame { public DarkenedGameView() { setTitle("区域变暗效果"); setSize(800, 600); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setLocationRelativeTo(null); // 创建主面板,包含游戏内容和遮罩层 JLayeredPane layeredPane = new JLayeredPane(); layeredPane.setLayout(new OverlayLayout(layeredPane)); // 游戏内容面板(模拟游戏画面) GameContentPanel gamePanel = new GameContentPanel(); gamePanel.setOpaque(true); gamePanel.setBounds(0, 0, getWidth(), getHeight()); // 遮罩面板(实现变暗效果) DarkeningOverlay overlay = new DarkeningOverlay(); overlay.setOpaque(false); // 必须设置为透明 overlay.setBounds(0, 0, getWidth(), getHeight()); // 添加到分层窗格 layeredPane.add(gamePanel, JLayeredPane.DEFAULT_LAYER); layeredPane.add(overlay, JLayeredPane.PALETTE_LAYER); setContentPane(layeredPane); // 添加鼠标移动监听器,使变暗区域跟随鼠标 overlay.addMouseMotionListener(new java.awt.event.MouseMotionAdapter() { public void mouseMoved(java.awt.event.MouseEvent evt) { overlay.setDarknessCenter(evt.getX(), evt.getY()); } }); } public static void main(String[] args) { SwingUtilities.invokeLater(() -> { new DarkenedGameView().setVisible(true); }); } } // 游戏内容面板(模拟游戏画面) class GameContentPanel extends JPanel { @Override protected void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2d = (Graphics2D) g; // 绘制背景(模拟游戏场景) g2d.setColor(new Color(100, 149, 237)); // 背景色 g2d.fillRect(0, 0, getWidth(), getHeight()); // 绘制一些游戏元素 g2d.setColor(Color.RED); g2d.fillOval(100, 100, 80, 80); g2d.setColor(Color.GREEN); g2d.fillRect(300, 200, 120, 80); g2d.setColor(Color.BLUE); g2d.fillRoundRect(500, 150, 100, 100, 30, 30); // 绘制文字 g2d.setColor(Color.WHITE); g2d.setFont(new Font("Arial", Font.BOLD, 24)); g2d.drawString("游戏场景", 350, 50); } } // 遮罩层实现变暗效果 class DarkeningOverlay extends JPanel { private int centerX = 400; private int centerY = 300; private int radius = 150; private float darkness = 0.7f; // 变暗程度 (0-1) public void setDarknessCenter(int x, int y) { centerX = x; centerY = y; repaint(); } @Override protected void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2d = (Graphics2D) g.create(); // 设置抗锯齿 g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); // 创建全屏的暗色矩形 Area darkArea = new Area(new Rectangle2D.Double(0, 0, getWidth(), getHeight())); // 创建明亮的圆形区域("洞") Ellipse2D brightCircle = new Ellipse2D.Double( centerX - radius, centerY - radius, radius * 2, radius * 2 ); // 从暗色区域中减去明亮区域 darkArea.subtract(new Area(brightCircle)); // 设置半透明黑色 g2d.setColor(new Color(0, 0, 0, darkness)); // 填充变暗区域 g2d.fill(darkArea); // 可选:绘制明亮区域的边界 g2d.setColor(Color.YELLOW); g2d.setStroke(new BasicStroke(2)); g2d.draw(brightCircle); g2d.dispose(); } } ``` ## 代码解释 ### 1. 整体结构 - `DarkenedGameView`:主窗口类,设置窗口属性和布局 - `GameContentPanel`:模拟游戏内容的背景面板 - `DarkeningOverlay`:实现变暗效果的遮罩层 ### 2. 实现原理 1. **分层布局**:使用`JLayeredPane`将游戏面板和遮罩层分离 2. **遮罩技术**: - 创建一个覆盖整个屏幕的半透明黑色矩形 - 在矩形中"挖"一个圆形区域(使用`Area.subtract()`方法) - 挖掉的部分保持透明,显示下方的游戏内容 3. **动态效果**:通过监听鼠标移动,更新明亮区域的位置 ### 3. 关键组件 - **GameContentPanel**:模拟游戏场景,绘制基本图形 - **DarkeningOverlay**: - `setDarknessCenter()`:更新明亮区域中心 - `paintComponent()`:绘制遮罩效果 - 使用`Area`类进行几何运算(减法操作) - 设置半透明颜色:`new Color(0, 0, 0, darkness)`,其中alpha值控制暗度 ### 4. 效果说明 - 整个游戏画面被半透明黑色覆盖 - 以鼠标位置为中心,半径为150像素的圆形区域保持明亮 - 明亮区域边缘有黄色边框标识 - 暗度可通过修改`darkness`变量调整(0为完全透明,1为完全不透明) ## 扩展功能建议 1. **动态调整明亮区域大小**:添加鼠标滚轮监听,动态调整半径 2. **多种形状的明亮区域**:支持矩形、多边形等形状 3. **渐变边缘**:使用RadialGradientPaint实现从明亮到黑暗的平滑过渡 4. **多个明亮区域**:支持同时显示多个明亮区域 5. **性能优化**:对于复杂游戏,使用缓冲图像减少重绘开销
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值