日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 综合教程 >内容正文

综合教程

蜂窝状网格的定位方法(转)

發(fā)布時(shí)間:2023/12/15 综合教程 27 生活家
生活随笔 收集整理的這篇文章主要介紹了 蜂窝状网格的定位方法(转) 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

源:蜂窩狀網(wǎng)格的定位方法

所謂蜂窩狀網(wǎng)格,也就是由多個(gè)六邊形組成的類似蜂窩的網(wǎng)格,在一些游戲地圖編輯器,手機(jī)觸摸屏,泡泡龍游戲等場(chǎng)景可以看到使用這種蜂窩網(wǎng)格。對(duì)于普通的矩形網(wǎng)格來(lái)說(shuō)(例如俄羅斯方塊,貪吃蛇的棋盤),由于屏幕和位圖在邏輯上的點(diǎn)陣模型,使得矩形網(wǎng)格的定位非常簡(jiǎn)便。矩形網(wǎng)格如果按照邊連接,具有 4 臨域(上下左右),而按照頂點(diǎn)連接,具有 8 臨域(在前者基礎(chǔ)上加上對(duì)角線);蜂窩網(wǎng)格的行間是一種錯(cuò)位關(guān)系,這使得我們編程建立數(shù)據(jù)結(jié)構(gòu)模型時(shí)帶來(lái)一點(diǎn)不便。下面僅從直觀觀察描述該網(wǎng)格(實(shí)際編程實(shí)現(xiàn)時(shí)還需要根據(jù)具體情況而定)。蜂窩網(wǎng)格具有 6 臨域,例如在下面的圖中,就是左,右,上偏左,上偏右,下偏左,下偏右。當(dāng)我們把蜂窩網(wǎng)格的數(shù)據(jù)也用數(shù)組存儲(chǔ)時(shí),蜂窩網(wǎng)格的臨域和存儲(chǔ)結(jié)構(gòu)有關(guān)。如下圖在行間交錯(cuò)的情況下,6 臨域是在 8 臨域 的基礎(chǔ)上去掉了兩個(gè)元素(去掉的元素根據(jù)所在奇數(shù)行和偶數(shù)行有所不同),在編程時(shí)這些是需要注意的地方。

  蜂窩網(wǎng)格的捕獲并不是那么直觀的,本文將講解如何在蜂窩網(wǎng)格定位,換句話說(shuō),也就是給定一個(gè)屏幕坐標(biāo),需要判斷哪個(gè)網(wǎng)格被該坐標(biāo)選中。首先我們來(lái)看蜂窩網(wǎng)格定位的原理,由下圖所示:


在上面的蜂窩網(wǎng)格上,我用藍(lán)色線條繪制了一張矩形網(wǎng)格(暫時(shí)稱為網(wǎng)格A)。并用藍(lán)色圓點(diǎn)在圖上標(biāo)記了每個(gè)蜂窩網(wǎng)格的中心點(diǎn)。我們根據(jù)給定的坐標(biāo)(x,y)可以首先定位到網(wǎng)格A中的某個(gè)矩形網(wǎng)格,然后觀察“網(wǎng)格A”和“蜂窩網(wǎng)格”的關(guān)系可以發(fā)現(xiàn),每個(gè)網(wǎng)格A的矩形網(wǎng)格的邊緣上都分布了三個(gè)蜂窩網(wǎng)格的中心點(diǎn)。這樣我們就可以在這三個(gè)點(diǎn)中找出與(x,y)點(diǎn)距離最近的點(diǎn),也就完成了蜂窩網(wǎng)格定位。
需要注意的是,蜂窩網(wǎng)格由于存在一種錯(cuò)位關(guān)系,因此蜂窩網(wǎng)格的中心點(diǎn)落到矩形網(wǎng)格A上時(shí),是行間交替變化的。例如在我所畫(huà)的這張圖上,我在圖片右側(cè)繪制除了網(wǎng)格A的縱坐標(biāo)為奇數(shù)和偶數(shù)時(shí)的蜂窩點(diǎn)分布情況。在捕獲蜂窩網(wǎng)格時(shí),必須針對(duì)這一點(diǎn)特別處理。
網(wǎng)格A中的單個(gè)矩形網(wǎng)格寬度和高度在代碼中分別是 g_unitx 和 g_unity; 它們分別是 網(wǎng)格A 在兩個(gè)方向上的長(zhǎng)度單位。 假設(shè)六邊形的邊長(zhǎng)為 a ,則:
g_unitx = a * sqrt (3) ; g_unity = a * (3/2) ;
下面我們就給出捕獲蜂窩網(wǎng)格的重要代碼: void GetCell(int x, int y, int *lpCellX, int *lpCellY); (x,y)通常為鼠標(biāo)的當(dāng)前位置,調(diào)用后,通過(guò) lpCellX 和 lpCellY 參數(shù)返回被捕獲的網(wǎng)格的中心點(diǎn)坐標(biāo)。

#pragma once
#include "stdafx.h"

//蜂窩網(wǎng)格的定位方法 -- by hoodlum1980
//假設(shè)六邊形的邊長(zhǎng)為a;


//兩個(gè)方向的矩形定位的基本單位
#define unitx(a)    ((a)*1.7320508)  //sqrt(3) * a
#define unity(a)    ((a)*1.5)                    //1.5 * a


//兩個(gè)方向的矩形網(wǎng)格基本單位
double g_unitx;
double g_unity;
double g_MinDistance2;     // (a*sqrt(3)/2)^2

//設(shè)置六邊形的邊長(zhǎng)
void SetCellSize(int a)
{
    if(a>0)
    {
        g_unitx = unitx(a);
        g_unity = unity(a);
        
        //二分之根號(hào)3 邊長(zhǎng)的平方,如果距離比它還小,就必然捕獲
        g_MinDistance2 = a*a*0.75;
    }
}


//求取兩個(gè)點(diǎn)的距離平方
inline int distance2(int x1, int y1, int x2, int y2)
{
    return ((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1));
}


//輸入鼠標(biāo)按下的點(diǎn)坐標(biāo)(x,y)
//返回被捕獲六邊形的中心坐標(biāo)
void GetCell(int x, int y, int *lpCellX, int *lpCellY)
{
    //位于矩形網(wǎng)格邊線上的三個(gè)CELL中心點(diǎn)
    POINT points[3];
    //當(dāng)前距離
    int dist;
    int mindist= (int)(g_MinDistance2 * 100); //一個(gè)非常大的值
    int i, index;//index:被捕獲的索引
    //計(jì)算出鼠標(biāo)點(diǎn)位于哪一個(gè)矩形網(wǎng)格中
    int cx = (int)(x/g_unitx);
    int cy = (int)(y/g_unity);
    
    points[0].x = (int)(g_unitx * cx);
    points[1].x = (int)(g_unitx * (cx+0.5));
    points[2].x = (int)(g_unitx * (cx+1));
    //根據(jù)cy是否是偶數(shù),決定三個(gè)點(diǎn)的縱坐標(biāo)
    if(cy % 2 == 0)
    {
        //偶數(shù)時(shí),三個(gè)點(diǎn)組成倒立三角
        points[0].y = points[2].y = (int)(g_unity * cy);
        points[1].y = (int)(g_unity * (cy+1));
    }    
    else
    {
        //奇數(shù)時(shí),三個(gè)點(diǎn)組成正立三角
        points[0].y = points[2].y = (int)(g_unity * (cy+1));
        points[1].y = (int)(g_unity * cy);
    }
    
    //現(xiàn)在找出鼠標(biāo)距離哪一個(gè)點(diǎn)最近
    for(i=0;i<3;i++)
    {
        //求出距離的平方
        dist = distance2(x,y, points[i].x, points[i].y);
        
        //如果已經(jīng)肯定被捕獲
        if(dist < g_MinDistance2)
        {
            index = i;
            break;
        }
        
        //更新最小距離值和索引
        if(dist < mindist)
        {
            mindist = dist;
            index = i;
        }
    }    
    
    //現(xiàn)在index 就是被捕獲的結(jié)果
    *lpCellX = points[index].x;
    *lpCellY = points[index].y;    
}

//給出蜂窩CELL的中心點(diǎn)和邊長(zhǎng)a,填充Cell的六邊形的六個(gè)端點(diǎn)

void GetCellPoints(int cellx, int celly, int a, POINT *lpPoints)
{
    if(lpPoints == NULL) return;
        
    lpPoints[0].x = cellx;
    lpPoints[0].y = celly - a;
    
    lpPoints[1].x = cellx + (int)(g_unitx*0.5);
    lpPoints[1].y = celly - a/2; 
    
    lpPoints[2].x = lpPoints[1].x;
    lpPoints[2].y = celly + a/2;
    
    lpPoints[3].x = cellx;
    lpPoints[3].y = celly + a;
    
    lpPoints[4].x = cellx - (int)(g_unitx*0.5);
    lpPoints[4].y = celly + a/2;
    
    lpPoints[5].x = lpPoints[4].x;
    lpPoints[5].y = celly - a/2;
}

除了上面我實(shí)現(xiàn)的距離法以外,我們還可以根據(jù)角度法,求出被捕獲的CELL;原理如下圖所示:

  

  如上圖所示,很顯然,同樣要區(qū)分 y 是偶數(shù)還是奇數(shù)。這里我們就其中一種情況討論,在上圖中,我們可以很容易獲取到三個(gè) CELL 的交界點(diǎn)的坐標(biāo):
  ox = g_unitx * x + a * sqrt(3)/2;
  oy = g_unity * y + a/2;

  然后我們求出鼠標(biāo)點(diǎn)和交界點(diǎn)的偏離12點(diǎn)的角度值:(需要考慮y軸和笛卡爾坐標(biāo)的方向相反,還要考慮點(diǎn)所在的象限,這里我們簡(jiǎn)單起見(jiàn),不去討論)

  alpha = 90 - atan( (oy - y) / (x - ox)) ;
  if (alpha < 0) alpha += 180 ;

  然后根據(jù)該角度落在的區(qū)間,得出被捕獲的 CELL 的中心點(diǎn)坐標(biāo);
  這種實(shí)現(xiàn)方法需要考慮的情況要比距離法更復(fù)雜,不易讀一些,因此這里我就不去嘗試寫(xiě)出完成的代碼了。

下面我給出一個(gè) Windows 應(yīng)用程序作為上面的代碼的演示,該程序首先繪制一副蜂窩網(wǎng)格圖背景,然后當(dāng)鼠標(biāo)在窗口上移動(dòng)時(shí),窗口實(shí)時(shí)的反饋被鼠標(biāo)捕獲的網(wǎng)格(用藍(lán)色顯示),程序運(yùn)行效果如圖:

該范例的源代碼下載鏈接:
http://files.cnblogs.com/hoodlum1980/BeehiveCell.rar

總結(jié)

以上是生活随笔為你收集整理的蜂窝状网格的定位方法(转)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。