js 基于可视区域 创建展示区域对应的经纬度二维数组

本文介绍了一种根据指定地理范围创建经纬度二维数组的方法,包括如何定义和初始化该数组,以便于处理地理数据。

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

本篇文章主要是分享下基于地图区域创建经纬度二维数组,需要的朋友可以过来参考下

接上个文章, 基于 地图区域,算出这个展示区域对应的点。

经纬度的变化关系:  XY页面展示上, 从左到右维度是增加 如: 106  -> 107 , 从上到下经度是减小  如:30 ->29 

创建的时候需要确定从哪开始, 附上代码,如下:

 

function getSizePointsData (latMin,latMax,lngMin,lngMax,lngStep,latStep){ // 区域的最小经度,最大经度,最小维度,最大维度,维度要画多少格,经度要画多少格
                    
  
          var viewAreaMapPoints=new Array();
          var lngValue = (lngMax - lngMin)/lngStep;  
          var latValue = (latMax - latMin)/latStep; 

          for(var k=0;k<latStep;k++){
                viewAreaMapPoints[k]=new Array();
                for(var j=0;j<lngStep;j++){
                     viewAreaMapPoints[k][j]= {drawIDs:[],count:0,lng:lngMin + j*lngValue,lat:latMax - k*latValue};
                }
          }
 }

这个有什么用呢,看之前的文章:  主要看思路:区域数据去重 + JavaScript一次性展示几万条数据实例代码

 

 

js二维数组定义和初始化的三种方法总结 ,可以参考 : http://www.jb51.net/article/47528.htm    ,不搬了

转载于:https://www.cnblogs.com/jshare/p/6773639.html

<think>我们已知起点和终点的经纬度,需要在Cesium中绘制一条向上的贝塞尔曲线(即拱形曲线)。由于Cesium本身没有直接提供绘制贝塞尔曲线的函数,我们需要自己计算贝塞尔曲线的控制点,然后使用折线(或实体)来绘制。贝塞尔曲线通常使用多个控制点。对于一条三次贝塞尔曲线,需要4个点:起点、两个控制点、终点。为了形成向上的曲线,我们需要在起点和终点之间的中点上方添加控制点。具体步骤:1.将起点和终点的经纬度转换为笛卡尔坐标(Cartesian3)。2.计算起点和终点之间的中点(在笛卡尔坐标系下),然后将该点沿法线方向(即地球表面向上的方向)升高一定高度,作为中间的控制点。实际上,对于三次贝塞尔曲线,我们需要两个控制点。常见的做法是:将起点到终点的方向向量,然后分别从起点和终点沿该方向的一定比例处升高作为控制点。但是,我们也可以使用二次贝塞尔曲线(三个点:起点、一个控制点、终点),这样更简单。不过Cesium的折线不支持直接绘制贝塞尔曲线,所以我们需要通过采样点来模拟曲线。这里我们选择三次贝塞尔曲线,因为它更灵活。我们可以这样设置控制点:控制点1:起点沿着起点到终点的方向移动1/3的距离,然后向上提升一定高度。控制点2:起点沿着起点到终点的方向移动2/3的距离,然后向上提升一定高度。另一种方法是:取起点和终点的中点,然后将其提升到一定高度作为中间的控制点(二次贝塞尔),然后采样点。由于Cesium中绘制曲线需要一系列点,因此我们将曲线离散成多个点,然后用这些点连成折线。算法:1.将起点(lon1,lat1)和终点(lon2,lat2)转换为Cartesian3:startCartesian,endCartesian。2.计算中点,并将其向上抬升作为控制点(对于二次贝塞尔曲线):-先求起点和终点的笛卡尔坐标的中点:midCartesian=(startCartesian+endCartesian)/2-然后,将中点沿法线方向(即归一化后的midCartesian方向)提升一定高度,得到控制点controlCartesian。但是,对于三次贝塞尔曲线,我们需要两个控制点。我们可以这样:-将起点到终点的向量分为三段,在1/3和2/3处设置控制点,并抬高。实际上,我们可以这样:controlPoint1=从起点沿起点到终点方向移动1/3距离的点,然后抬高。controlPoint2=从起点沿起点到终点方向移动2/3距离的点,然后抬高。然而,在三维空间中,我们需要保证控制点在地球上方。另一种思路是在起点和终点的连线上的两个点(比如1/3和2/3处)抬高作为控制点。具体步骤(使用三次贝塞尔曲线):1.将起点和终点转换为笛卡尔坐标。2.计算起点到终点的向量:direction=endCartesian-startCartesian。3.计算两个控制点:controlPoint1=startCartesian+direction*(1/3)+normalVector*height1;controlPoint2=startCartesian+direction*(2/3)+normalVector*height2;其中,normalVector可以是地球表面在该点的法向量(即归一化的Cartesian3向量),但注意:在起点和终点处的法向量可能不同。我们可以用起点、终点和中间点的法向量?为了简单,我们可以使用中点的法向量,即归一化的(startCartesian+endCartesian)向量,然后乘以一个高度。但是,这样计算出的点可能不在球面上。我们可以在笛卡尔坐标系中做插值,然后抬高,这里抬高就是沿着该点的法线方向(即该点的归一化向量)乘以一个高度增量。4.使用三次贝塞尔曲线公式,在0到1之间取多个t值,计算曲线上的点:B(t)=(1-t)^3*P0+3*(1-t)^2*t*P1+3*(1-t)*t^2*P2+t^3*P3其中P0是起点,P3是终点,P1和P2是控制点。5.将计算出的点(笛卡尔坐标数组)添加到Cesium的折线或实体中。注意:我们抬高控制点的时候,抬高的高度应该是相对于地球表面的高度。但是起点和终点在地球表面,所以控制点的高度应该是一个相对高度(例如比起点终点高1000米)。步骤详细:步骤1:转换起点和终点startCartographic=Cesium.Cartographic.fromDegrees(lon1,lat1)startCartesian=Cesium.Cartesian3.fromRadians(startCartographic.longitude,startCartographic.latitude,startCartographic.height)同理,终点转换。步骤2:计算中点(在笛卡尔坐标系下)并计算中点的法线方向midCartesian=Cesium.Cartesian3.lerp(startCartesian,endCartesian,0.5,newCesium.Cartesian3());midNormal=Cesium.Cartesian3.normalize(midCartesian,newCesium.Cartesian3());步骤3:计算两个控制点(这里我们使用三次贝塞尔,需要两个控制点)我们选择在1/3和2/3处抬高://1/3处的点temp1=Cesium.Cartesian3.lerp(startCartesian,endCartesian,1/3,newCesium.Cartesian3());//然后沿着该点的法线方向(其实这里我们近似使用midNormal)抬高,因为严格来说每个点都有自己的法线,但为了简单,使用同一个法线方向。controlPoint1=Cesium.Cartesian3.add(temp1,Cesium.Cartesian3.multiplyByScalar(midNormal,height,newCesium.Cartesian3()),newCesium.Cartesian3());//2/3处的点temp2=Cesium.Cartesian3.lerp(startCartesian,endCartesian,2/3,newCesium.Cartesian3());controlPoint2=Cesium.Cartesian3.add(temp2,Cesium.Cartesian3.multiplyByScalar(midNormal,height,newCesium.Cartesian3()),newCesium.Cartesian3());注意:height是抬高的高度(单位:米)。但这里temp1和temp2的坐标是笛卡尔坐标,而height是相对于地球表面的高度?实际上,temp1和temp2的位置在地球表面(高度0),所以我们直接加上height*midNormal,因为midNormal是单位向量,乘以height就是抬高height米。步骤4:采样贝塞尔曲线点t从0到1,步长0.01,计算贝塞尔曲线的点。步骤5:创建折线viewer.entities.add({polyline:{positions:positions,//步骤4计算的笛卡尔坐标数组width:2.0,material:Cesium.Color.RED}});但是,这里有一个问题:我们使用笛卡尔坐标的线性插值(lerp)得到的1/3和2/3处的点,是否是在地球表面?实际上,我们之前将起点和终点转换到笛卡尔坐标时,高度为0(即在地球表面)。而lerp是在两个笛卡尔坐标之间线性插值,得到的点也在地球表面上(因为笛卡尔坐标系中,从球面一点到另一点的直线段并不在地球表面,而是穿越地球内部?)。所以,我们实际上需要的是沿地球表面的曲线?但是用户要求向上的拱形,所以实际上我们不需要沿着地表,而是直线段的上方拱起。我们当前的方法是在直线段(连接起点和终点的直线)的上方抬高,这样形成的曲线是在一个平面内的拱形。但是,由于地球是球体,如果起点和终点距离很远,直线段会穿越地球内部,而我们希望拱形是在地球外部,所以我们应该沿大圆路径(测地线)上方拱起?这样更符合实际情况。然而,计算测地线上的点然后抬高,会复杂一些。由于用户要求不高,我们可以先使用直线段上方拱起。如果距离不远,效果可以接受。另外,如果我们希望曲线完全在地球外部,我们可以这样做:1.计算起点和终点之间的测地线(大圆)路径,并采样多个点(这些点在地球表面)。2.将这些采样点抬高到某个高度(比如10000米),形成一条高空的大圆路径。3.然后在这条高空路径上应用贝塞尔曲线?或者直接使用这些点作为路径?但是题目要求是贝塞尔曲线,所以我们可以将起点、终点和中间的采样点作为控制点,构建更高阶的贝塞尔曲线?这可能会很复杂。这里为了简单,我们还是采用在直线段上方拱起的方法。如果距离较远(比如超过几百公里),可能会看起来不太自然(因为直线穿越地球内部,而拱形曲线也会穿越地球内部)。所以我们还需要将拱形曲线抬高到一定高度,以避免穿越地球内部。一种改进方法是:我们首先将起点和终点都抬高到一定高度(例如10000米),然后在这两个点之间构造贝塞尔曲线,这样整个曲线都在高空,不会穿越地球内部。步骤调整(改进):1.将起点和终点都抬高到同一个高度(比如10000米)。startCartographic.height=10000;startCartesian=Cesium.Cartesian3.fromRadians(startCartographic.longitude,startCartographic.latitude,startCartographic.height);//同理终点2.然后按照之前的步骤计算两个控制点(也在10000米高度上方再抬高,比如15000米?)注意:这样控制点的高度就比起点终点高了5000米。//计算起点终点之间的1/3和2/3处的点(在笛卡尔坐标系中直线插值)//然后将这些点再向上抬高(相对于10000米表面再抬高5000米?)注意:这里我们抬高的参考面并不是地球表面,而是起点终点所在的高度的平面。但是为了简单,我们还是沿法线方向抬高。3.计算贝塞尔曲线的点。这样整个曲线都在10000米以上,不会穿越地球内部。但是,在球面上,沿着法线方向抬高后,实际是在球心到该点连线的延长线上。所以起点、终点、控制点都是在一个球面上(10000米高度球面)或者再高一点。具体代码步骤:步骤1:定义起点和终点的经纬度,并设置一个基础高度(比如10000米)。varstartCartographic=Cesium.Cartographic.fromDegrees(lon1,lat1,10000);varendCartographic=Cesium.Cartographic.fromDegrees(lon2,lat2,10000);varstart=Cesium.Cartesian3.fromRadians(startCartographic.longitude,startCartographic.latitude,startCartographic.height);varend=Cesium.Cartesian3.fromRadians(endCartographic.longitude,endCartographic.latitude,endCartographic.height);步骤2:计算中点(在起点和终点的笛卡尔坐标之间线性插值),然后计算该点的法向量(即归一化的中点向量)varmid=Cesium.Cartesian3.lerp(start,end,0.5,newCesium.Cartesian3());varmidNormal=Cesium.Cartesian3.normalize(mid,newCesium.Cartesian3());步骤3:计算两个控制点(在起点和终点之间的1/3和2/3处,然后沿着midNormal方向再抬高5000米):varcontrolHeight=15000;//因为起点终点在10000米,再抬高5000米达到15000米//计算1/3处的点vartemp1=Cesium.Cartesian3.lerp(start,end,1/3,newCesium.Cartesian3());//计算该点处的实际高度(相对于球心)?我们不需要计算,直接加上抬高向量//但是注意:temp1的位置是在起点和终点连线上,高度并不精确是10000米(因为线性插值在笛卡尔坐标系中,高度并不是恒定的10000米)。所以我们应该先将其投影到10000米高度的球面上?或者,我们可以用另一种方法:将temp1归一化,然后乘以(地球半径+10000米)?这样会保证在10000米高度上。但我们这里为了简单,不再做投影,直接用线性插值的结果,然后加上抬高向量(这样高度会有所变化,但差别不大)。//所以,控制点1:将temp1投影到10000米的球面上?或者,我们直接加一个向量(midNormal*5000)?因为temp1已经在10000米高度附近,我们再加5000米的抬高量,应该达到15000米高度。//然而,这样做并不精确。更精确的做法:将temp1归一化,然后乘以(地球半径+15000米)。但Cesium中,地球半径可以取6378137米。//这里我们采用归一化后乘以半径+高度的方法。varearthRadius=6378137.0;//椭球长半轴,Cesium中默认的椭球是WGS84vartemp1Normal=Cesium.Cartesian3.normalize(temp1,newCesium.Cartesian3());control1=Cesium.Cartesian3.multiplyByScalar(temp1Normal,earthRadius+controlHeight,newCesium.Cartesian3());//同理计算2/3处的点vartemp2=Cesium.Cartesian3.lerp(start,end,2/3,newCesium.Cartesian3());vartemp2Normal=Cesium.Cartesian3.normalize(temp2,newCesium.Cartesian3());control2=Cesium.Cartesian3.multiplyByScalar(temp2Normal,earthRadius+controlHeight,newCesium.Cartesian3());但是,我们注意到:起点和终点我们也是通过同样方式构造的(即用高度乘以法向量),所以起点和终点是精确的。那么我们的控制点应该也是用同样的方式构造。所以,我们不应该使用线性插值得到的temp1,而是应该计算从球心到temp1方向的单位向量,然后乘以(地球半径+目标高度)。然而,我们之前已经将起点和终点转换成了笛卡尔坐标(从球心到表面点的向量乘以半径+高度),所以起点和终点之间的线性插值temp1并不在球面上。因此,我们需要重新计算起点和终点连线上的点在球面上的对应点(即沿着球心到该点的方向与球面相交的点)?这没有必要,因为我们的目标是构建一条平滑的曲线,而不是严格的球面曲线。因此,我们可以简化处理,直接使用线性插值得到的点作为控制点的基础位置,然后归一化并乘以(地球半径+控制点高度)。这样控制点就在球面上方15000米处,但位置与线性插值点在同一方向。步骤4:现在,起点、终点和控制点都在不同高度(起点终点10000米,控制点15000米)。然后我们采样三次贝塞尔曲线。注意:贝塞尔曲线公式是在笛卡尔坐标空间中进行的,所以直接代入公式即可。步骤5:将采样点用于绘制折线。但是,这样绘制出的曲线会穿越地球吗?因为起点和终点在10000米,控制点在15000米,所以曲线整体应该都在10000米以上。接下来,我们编写代码:我们使用Cesium.Entity的折线(polyline)来绘制。折线是由一系列点组成的。代码实现:注意:以下代码仅为示例,可能需要在Cesium环境中运行。```javascriptfunctionaddBezierCurve(viewer,lon1,lat1,lon2,lat2){varearthRadius=6378137.0;//地球椭球长半轴,单位米varbaseHeight=10000;//基础高度(米)varcontrolHeight=15000;//控制点高度(米)//创建起点和终点的Cartographic(弧度制)varstartCartographic=Cesium.Cartographic.fromDegrees(lon1,lat1);varendCartographic=Cesium.Cartographic.fromDegrees(lon2,lat2);//转换为笛卡尔坐标(在baseHeight高度)varstart=Cesium.Cartesian3.fromRadians(startCartographic.longitude,startCartographic.latitude,baseHeight);varend=Cesium.Cartesian3.fromRadians(endCartographic.longitude,endCartographic.latitude,baseHeight);//计算1/3和2/3处的点(在笛卡尔坐标系中线性插值)vartemp1=Cesium.Cartesian3.lerp(start,end,1/3,newCesium.Cartesian3());vartemp2=Cesium.Cartesian3.lerp(start,end,2/3,newCesium.Cartesian3());//归一化并乘以半径+控制点高度,得到控制点varcontrol1=scaleToHeight(temp1,earthRadius+controlHeight);varcontrol2=scaleToHeight(temp2,earthRadius+controlHeight);//采样贝塞尔曲线(三次)varpositions=[];for(vart=0;t<=1;t+=0.01){//三次贝塞尔曲线公式varB=bezier3(t,start,control1,control2,end);positions.push(B);}//添加实体viewer.entities.add({polyline:{positions:positions,width:5,material:Cesium.Color.RED}});}//将一个笛卡尔坐标归一化后乘以指定高度(半径+高度)functionscaleToHeight(cartesian,height){varnormal=Cesium.Cartesian3.normalize(cartesian,newCesium.Cartesian3());returnCesium.Cartesian3.multiplyByScalar(normal,height,newCesium.Cartesian3());}//三次贝塞尔曲线:t在[0,1],P0,P1,P2,P3functionbezier3(t,P0,P1,P2,P3){//B(t)=(1-t)^3*P0+3*(1-t)^2*t*P1+3*(1-t)*t^2*P2+t^3*P3vart1=1-t;vart1_2=t1*t1;vart1_3=t1_2*t1;vart2=t*t;vart3=t2*t;//分别计算四项varpart0=Cesium.Cartesian3.multiplyByScalar(P0,t1_3,newCesium.Cartesian3());varpart1=Cesium.Cartesian3.multiplyByScalar(P1,3*t1_2*t,newCesium.Cartesian3());varpart2=Cesium.Cartesian3.multiplyByScalar(P2,3*t1*t2,newCesium.Cartesian3());varpart3=Cesium.Cartesian3.multiplyByScalar(P3,t3,newCesium.Cartesian3());//相加varresult=Cesium.Cartesian3.add(part0,part1,newCesium.Cartesian3());result=Cesium.Cartesian3.add(result,part2,result);result=Cesium.Cartesian3.add(result,part3,result);returnresult;}```注意:这里我们使用线性插值后归一化再乘以高度的方法得到控制点。这样控制点就会在距离球心(earthRadius+controlHeight)的位置。这样绘制的曲线是一个拱形,但是可能不够平滑(如果起点和终点距离很远,1/3和2/3处的控制点会使得曲线有一个尖峰?)。我们可以尝试调整控制点的高度(比如控制点高度更高,拱形更明显)或者调整控制点的位置(比如使用其他比例的中间点)来改变曲线形状。另外,我们还可以使用二阶贝塞尔曲线(一个控制点):控制点在中点上方贝塞尔公式:B(t)=(1-t)^2*P0+2*(1-t)*t*P1+t^2*P2修改:控制点取中点:mid=(start+end)/2,然后归一化乘以控制点高度(15000米)采样点公式改为二阶代码类似,这里不再重复。以上是一种实现方式。需要注意的是,由于我们使用的是直线插值,所以当起点和终点距离很远时,中间点会在地球内部(但实际上我们使用基础高度10000米,所以不会在地表以下),控制点也在15000米高度,所以整个曲线都在空中。希望这个方案对你有帮助。</think> 在 Cesium 中根据经纬度起点和终点绘制向上拱起的贝塞尔曲线,可以通过以下步骤实现: ### 解决思路 1. **计算中间控制点**:在起点和终点之间选择抬升点(如中点),并沿地球法线方向抬升到指定高度 2. **构建贝塞尔曲线**:使用三次贝塞尔曲线公式进行采样 3. **坐标转换**:使用 Cartographic 和 Cartesian3 进行经纬度与笛卡尔坐标转换 4. **创建实体**:用采样点生成 Polyline 实体 ### 代码实现 ```javascript function createBezierArc(startLon, startLat, endLon, endLat, height) { // 1. 坐标转换 const earthRadius = 6378137.0; // 地球半径 (WGS84) const startCartographic = Cesium.Cartographic.fromDegrees(startLon, startLat); const endCartographic = Cesium.Cartographic.fromDegrees(endLon, endLat); // 2. 转换到笛卡尔坐标 const start = Cesium.Cartesian3.fromRadians( startCartographic.longitude, startCartographic.latitude, earthRadius ); const end = Cesium.Cartesian3.fromRadians( endCartographic.longitude, endCartographic.latitude, earthRadius ); // 3. 计算抬升点(中点) const midPoint = new Cesium.Cartesian3(); Cesium.Cartesian3.lerp(start, end, 0.5, midPoint); const midNormal = Cesium.Cartesian3.normalize(midPoint, new Cesium.Cartesian3()); const controlPoint = Cesium.Cartesian3.add( midPoint, Cesium.Cartesian3.multiplyByScalar(midNormal, height, new Cesium.Cartesian3()), new Cesium.Cartesian3() ); // 4. 贝塞尔曲线采样(二次贝塞尔) const positions = []; for (let t = 0; t <= 1; t += 0.01) { // 贝塞尔公式: B(t) = (1-t)&sup2;P0 + 2(1-t)tP1 + t&sup2;P2 const t1 = 1 - t; const term0 = Cesium.Cartesian3.multiplyByScalar(start, t1 * t1, new Cesium.Cartesian3()); const term1 = Cesium.Cartesian3.multiplyByScalar(controlPoint, 2 * t1 * t, new Cesium.Cartesian3()); const term2 = Cesium.Cartesian3.multiplyByScalar(end, t * t, new Cesium.Cartesian3()); const point = Cesium.Cartesian3.add(term0, term1, new Cesium.Cartesian3()); Cesium.Cartesian3.add(point, term2, point); positions.push(point); } // 5. 创建曲线实体 viewer.entities.add({ polyline: { positions: positions, width: 5, material: new Cesium.PolylineGlowMaterialProperty({ glowPower: 0.2, color: Cesium.Color.CYAN }), arcType: Cesium.ArcType.NONE } }); } // 调用示例(起点北京,终点上海,抬升高度15km) createBezierArc(116.4, 39.9, 121.47, 31.23, 15000); ``` ### 关键说明 1. **曲线类型**:使用二次贝塞尔曲线(1个控制点) 2. **高度控制**: - `height` 参数控制拱起高度(单位:米) - 在法线方向抬升形成自然拱形 3. **采样精度**: - `t += 0.01` 控制曲线平滑度 - 可根据性能需求调整步长 ### 可视化效果 生成的曲线会呈现以下特征: 1. 起点和终点固定在地表 2. 中点在指定高度形成拱形顶点 3. 曲线保持在地球外部空间 4. 可通过材质参数调整颜色和发光效果 ### 进阶优化 1. **动态高度**:根据距离自动计算合适高度 ```javascript const distance = Cesium.Cartesian3.distance(start, end); const autoHeight = distance * 0.2; // 高度为距离的20% ``` 2. **三次贝塞尔曲线**:如需更多控制点可扩展为: ```javascript // 新增控制点 const controlPoint2 = ... // 三次贝塞尔公式 const t1 = 1 - t; const B = P0*t1³ + 3*P1*t*t1&sup2; + 3*P2*t&sup2;*t1 + P3*t³; ``` [^1]: 参考坐标转换原理
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值