有没有人知道我可以用来将Google地图中的放大Android API https://developers.google.com/maps/documentation/android-api/streetview转换为Google StreetView Image API中使用的FOV的公式:https://developers.google.com/maps/documentation/streetview/intro?
我在这里找到了几个旧公式:
然后我将它们进行测试,当我在Android手机上放大相机时,将计算FOV:
FOV1:3.9018*Math.pow(streetViewPanoramaCamera.zoom,2) - 42.432*streetViewPanoramaCamera.zoom + 123
FOV2:Math.abs(streetViewPanoramaCamera.zoom/5*108-120
FOV3:180/Math.pow(2,streetViewPanoramaCamera.zoom)
@Override
public void onStreetViewPanoramaCameraChange(StreetViewPanoramaCamera streetViewPanoramaCamera) {
Log.e("Pano", "Bearing: " + streetViewPanoramaCamera.bearing + " Tilt: " + streetViewPanoramaCamera.tilt +
" Zoom: " + streetViewPanoramaCamera.zoom +
" FOV1: "+ String.valueOf(3.9018*Math.pow(streetViewPanoramaCamera.zoom,2) - 42.432*streetViewPanoramaCamera.zoom + 123) +" FOV2: "+
Math.abs(streetViewPanoramaCamera.zoom/5*108-120) +" FOV3: "+ 180/Math.pow(2,streetViewPanoramaCamera.zoom) ) ;
}
在android上缩放0.0时,我们返回了以下FOV值:
09-27 15:53:52.322 E / Pano:方位:228.28955倾斜:14.516191放大: 0.0 FOV1:123.0 FOV2:120.0 FOV3:180.0
由于FOV的最大值为120,FOV2的公式最初看起来很有希望,但当我缩放2次时,它给出的值为76.8,远远低于实际值:
09-27 16:01:48.235 E / Pano:方位:223.11241倾斜:1.852709放大:2.0 FOV1:53.7432 FOV2:76.8 FOV3:45.0
这是2倍变焦后手机上的图像:
这是从FST 76.8(https://maps.googleapis.com/maps/api/streetview?size=600x300&location=-33.87365,151.20689&heading=223.11241&pitch=1.852709&fov=76.8&key=APIKEY)的Google Streetview Image API下载的图片:
这是在FOV 45(https://maps.googleapis.com/maps/api/streetview?size=600x300&location=-33.87365,151.20689&heading=223.11241&pitch=1.852709&fov=45&key=APIKEY)从Google Streetview Image API下载的图片:
我得到的最接近的是如果我做了FOV 26,但这是我猜测而不是使用公式 - 下图是在FOV 26:
答案 0 :(得分:1)
我最终不得不对该行进行回归以获得指数公式。
我使用这个网站并手动输入FOV和缩放值的数据点组合,这些数据点可以很好地协同工作:http://www.had2know.com/academics/regression-calculator-statistics-best-fit.html
我的数据点是:
120(0)
50(1)
45(1.2)
37(1.5)
26(2)
69(0.5)
78(0.3)
31(1.9)
为了获得更接近的公式,你可以不断增加更多"良好的适应性"数据点,但我没有时间 - 任何想要完善公式的人都可以尝试。
我得到了下面的公式,其中Y是FOV,X是缩放。
Y = 103.7587(0.5051 ^ X)
correlation = -0.9882
答案 1 :(得分:0)
您可以使用以下公式(JavaScript中的代码):
将 fov 转换为缩放:
File out = new File("Trina_NEW.xls")
的 <config evaluator="node-type" condition="acme:document">
<forms>
<form>
<field-visibility>
<show id="acme:anycustomproperty"/>
</field-visibility>
<appearance>
<field id="acme:anycustomproperty" label-id="xqw">
<control template='/org/alfresco/components/form/controls/textfield.ftl' />
<control-param name='maxlength'>5000</control-param>
<control template='/org/alfresco/components/form/controls/textarea.ftl' />
<control-param name='rows'>10</control-param>
<control-param name='columns'>10</control-param>
</field>
</appearance>
</form>
</forms>
</config>
强> zoom = Math.log(180/
将缩放转换为 fov :
fov
的 )/(Math.log(2))
强> fov = 180 / Math.pow(2,
答案 2 :(得分:0)
谷歌搜索这个答案我只能找到网络的公式。 Web是不同的,因为首先,文档中有一个Zoom vs FOV图表: https://developers.google.com/maps/documentation/javascript/streetview#TilingPanoramas
因此,人们可以想出一个公式。 Android文档没有这样的表格,人们用于网络的公式不适用于Android(甚至没有关闭)。
然而,有一些好消息,Android API中提供了此功能: StreetViewPanorama.orientationToPoint(StreetViewPanoramaOrientation orientation)
此功能允许我们提供方向,它将返回屏幕上该方向所在的点。该函数的文档说如果该方向不在屏幕上,它将返回null,但实际上我发现它将在屏幕的可视区域之外给出一个点;但是,如果我们知道屏幕尺寸,我们可以检查该点是否有效。通过循环180度,我们可以找到该范围的多少是可见的,因此可以看到视野。
警告:此功能效率低下。仅在变焦已更改时调用!
注意:下面的示例代码计算HORIZONTAL视野。要计算垂直视野,您需要进行一些更改。例如,将point.x更改为point.y,将screenSize.x的所有实例更改为screenSize.y,将streetViewPanoramaCamera.bearing的所有实例更改为streetViewPanoramaCamera.tilt,并更改所有实例:
orientation = new StreetViewPanoramaOrientation(streetViewPanoramaCamera.tilt, angleCheck);
为:
orientation = new StreetViewPanoramaOrientation(angleCheck, streetViewPanoramaCamera.bearing);
这是一个简单的方法,我们只需从-90度到+90度循环,并查看180度在可视区域中的多少(注意:这仅在倾斜度为0度时才有效,即用户没有抬头或向下看):
private StreetViewPanorama mStreetViewPanorama;
private float mZoom = -1f;
private int mFieldOfViewDegrees;
private void onOrientationUpdate(StreetViewPanoramaCamera streetViewPanoramaCamera) {
if (streetViewPanoramaCamera.zoom != mZoom) {
mFieldOfViewDegrees = getFieldOfView(streetViewPanoramaCamera);
mZoom = streetViewPanoramaCamera.zoom;
}
}
private int getFieldOfView(StreetViewPanoramaCamera streetViewPanoramaCamera) {
WindowManager windowManager = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
Display display = windowManager.getDefaultDisplay();
Point screenSize = new Point();
display.getSize(screenSize);
StreetViewPanoramaOrientation orientation;
Integer lowerFovDegrees = null;
Integer upperFovDegrees = null;
for (int angleCheck = (int) streetViewPanoramaCamera.bearing - 90;
angleCheck <= (int) streetViewPanoramaCamera.bearing + 90;
angleCheck++) {
orientation = new StreetViewPanoramaOrientation(streetViewPanoramaCamera.tilt, angleCheck);
Point point = mStreetViewPanorama.orientationToPoint(orientation);
if (lowerFovDegrees == null) {
if ((point != null) && (point.x >= 0)) {
lowerFovDegrees = angleCheck;
}
} else if (upperFovDegrees == null) {
if ((point == null) || (point.x > screenSize.x)) {
upperFovDegrees = angleCheck - 1;
break;
}
}
}
int fieldOfViewDegrees = upperFovDegrees - lowerFovDegrees;
return fieldOfViewDegrees;
}
但是,orientationToPoint()很昂贵,最多可以调用180次。我们可以使用二进制搜索来提高效率(虽然更复杂),并将其减少到更像~13次调用。在这种情况下,我使用递归函数来执行二进制搜索。还有一个限制,即水平赤道必须在视野中或不能精确计算FOV;在这种情况下,它返回null。只要用户没有向下或向下倾斜,这不是一个真正的问题,但如果他们这样做,FOV将返回null并且您需要隐藏任何依赖于FOV的UI元素准确的(或者它们不在正确的位置)。
private StreetViewPanorama mStreetViewPanorama;
private float mZoom = -1f;
private float mFieldOfViewDegrees;
private void onOrientationUpdate(StreetViewPanoramaCamera streetViewPanoramaCamera) {
if (streetViewPanoramaCamera.zoom != mZoom) {
Float fieldOfViewDegrees = getFieldOfView(streetViewPanoramaCamera);
if (fieldOfViewDegrees == null) { // If FOV cannot be determined, hide any overlay UI overlay elements so they don't display misaligned
mZoom = -1f;
// Hide UI overlay elements
} else {
mFieldOfViewDegrees = fieldOfViewDegrees;
mZoom = streetViewPanoramaCamera.zoom;
// Show UI overlay elements
}
}
}
/*
* Determine field of view. Must use roundabout way since the info is not provided directly.
* StreetViewPanorama.orientationToPoint() will tell us if a particular orientation is visible on the
* screen, so we can loop from looking left (-90) to right (+90) and see how much of the 180 degrees is in
* the field of view.
*
* This is is CPU intensive, so instead of a simple loop we use a recursive binary search, and make sure
* to only call this function when the zoom has changed.
*
* WARNING: This method of getting the FOV only works if the equator is still in view. If the user tilts
* too far down or up, it will return null.
*/
private Float getFieldOfView(StreetViewPanoramaCamera streetViewPanoramaCamera) {
WindowManager windowManager = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
Display display = windowManager.getDefaultDisplay();
Point screenSize = new Point();
display.getSize(screenSize);
// If the equator is no longer in view, FOV cannot be accurately calculated
StreetViewPanoramaOrientation orientation =
new StreetViewPanoramaOrientation(0, streetViewPanoramaCamera.bearing);
Point point = mStreetViewPanorama.orientationToPoint(orientation);
if (point.y < 0 || point.y > screenSize.y) {
return null;
}
Float lowerFovDegrees = getLowerFieldOfViewDegrees(
streetViewPanoramaCamera,
screenSize,
streetViewPanoramaCamera.bearing - 90f,
streetViewPanoramaCamera.bearing + 90f);
Float upperFovDegrees = getUpperFieldOfViewDegrees(
streetViewPanoramaCamera,
screenSize,
streetViewPanoramaCamera.bearing - 90f,
streetViewPanoramaCamera.bearing + 90f);
if ((lowerFovDegrees == null) || (upperFovDegrees == null)) return null;
float fieldOfViewDegrees = upperFovDegrees - lowerFovDegrees;
return fieldOfViewDegrees;
}
// Recursive binary search function
private Float getLowerFieldOfViewDegrees(StreetViewPanoramaCamera streetViewPanoramaCamera,
Point screenSize,
float startDegrees,
float endDegrees) {
StreetViewPanoramaOrientation orientation;
float midpointDegrees = (int) (startDegrees + ((endDegrees - startDegrees) / 2f));
orientation = new StreetViewPanoramaOrientation(0, midpointDegrees);
Point point = mStreetViewPanorama.orientationToPoint(orientation);
if ((point == null) || (point.x < 0)) {
if (endDegrees - midpointDegrees <= 1f) {
return endDegrees;
}
return getLowerFieldOfViewDegrees(
streetViewPanoramaCamera,
screenSize,
midpointDegrees,
endDegrees);
} else {
if (midpointDegrees - startDegrees <= 1f) {
return midpointDegrees;
}
return getLowerFieldOfViewDegrees(
streetViewPanoramaCamera,
screenSize,
startDegrees,
midpointDegrees);
}
}
// Recursive binary search function
private Float getUpperFieldOfViewDegrees(StreetViewPanoramaCamera streetViewPanoramaCamera,
Point screenSize,
float startDegrees,
float endDegrees) {
StreetViewPanoramaOrientation orientation;
float midpointDegrees = (int) (startDegrees + ((endDegrees - startDegrees) / 2f));
orientation = new StreetViewPanoramaOrientation(0, midpointDegrees);
Point point = mStreetViewPanorama.orientationToPoint(orientation);
if ((point == null) || (point.x > screenSize.x)) {
if (midpointDegrees - startDegrees <= 1f) {
return startDegrees;
}
return getUpperFieldOfViewDegrees(
streetViewPanoramaCamera,
screenSize,
startDegrees,
midpointDegrees);
} else {
if (endDegrees - midpointDegrees <= 1f) {
return midpointDegrees;
}
return getUpperFieldOfViewDegrees(
streetViewPanoramaCamera,
screenSize,
midpointDegrees,
endDegrees);
}
}
上述函数的粒度为最接近的度数。您可以对其进行修改以提供更小的粒度,但运行时间会更长。因为它已经导致图形口吃,所以我没有这样做。
我希望这可以帮助其他人,因为这似乎是一个常见的问题,我还没有看到它解决了Android。
答案 3 :(得分:0)
我找到了一个更好的方法,JavaScript 如下:
import android.content.Context;
import android.content.Intent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import java.util.ArrayList;
public class CourseAdapter extends RecyclerView.Adapter<CourseAdapter.Viewholder>{
private Context context;
private ArrayList<CourseModel> courseModelArrayList;
// Constructor
public CourseAdapter(Context context, ArrayList<CourseModel> courseModelArrayList) {
this.context = context;
this.courseModelArrayList = courseModelArrayList;
}
@NonNull
@Override
public CourseAdapter.Viewholder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
// to inflate the layout for each item of recycler view.
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.card_recycle_courses, parent, false);
return new Viewholder(view);
}
@Override
public void onBindViewHolder(@NonNull CourseAdapter.Viewholder holder, int position) {
// to set data to textview and imageview of each card layout
CourseModel model = courseModelArrayList.get(position);
holder.courseNameTV.setText(model.getCourse_name());
holder.courseDescriptionTV.setText("" + model.getCourse_description());
holder.courseIV.setImageResource(model.getCourse_image());
}
@Override
public int getItemCount() {
// this method is used for showing number
// of card items in recycler view.
return courseModelArrayList.size();
}
// View holder class for initializing of
// your views such as TextView and Imageview.
public class Viewholder extends RecyclerView.ViewHolder {
private ImageView courseIV;
private TextView courseNameTV, courseDescriptionTV;
public Viewholder(@NonNull View itemView) {
super(itemView);
courseIV = itemView.findViewById(R.id.idIVCourseImage);
courseNameTV = itemView.findViewById(R.id.idTVCourseName);
courseDescriptionTV = itemView.findViewById(R.id.idTVCourseDescription);
}
}
}
为我在移动设备上运行的 React Native 工作。但目前只在 iOS 上测试。