Commit 9ba97109ea03f955835e8e1bf8a0840329fa7953

Authored by 王通
1 parent 8cedaf34

1.加入导航点位信息接口(常规、绕改道)

src/main/java/com/bsth/entity/Detour.java 0 → 100644
  1 +package com.bsth.entity;
  2 +
  3 +import com.fasterxml.jackson.annotation.JsonIgnore;
  4 +import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
  5 +import org.hibernate.annotations.DynamicInsert;
  6 +import org.hibernate.annotations.DynamicUpdate;
  7 +
  8 +import javax.persistence.*;
  9 +import java.util.ArrayList;
  10 +import java.util.List;
  11 +
  12 +/**
  13 + * 绕改道实体类
  14 + * 对应数据库表 bsth_c_detour
  15 + */
  16 +@Entity
  17 +@Table(name = "bsth_c_detour")
  18 +@DynamicInsert
  19 +@DynamicUpdate
  20 +@JsonIgnoreProperties(ignoreUnknown = true)
  21 +public class Detour {
  22 +
  23 + // 主键
  24 + @Id
  25 + @GeneratedValue(strategy = GenerationType.IDENTITY)
  26 + @JsonIgnore
  27 + private Integer id;
  28 +
  29 + // 线路
  30 + private Integer line;
  31 +
  32 + // 版本号
  33 + @JsonIgnore
  34 + private Integer versions;
  35 +
  36 + // 上下行
  37 + private Integer direction;
  38 +
  39 + // 起点编码
  40 + @JsonIgnore
  41 + private String startStationCode;
  42 +
  43 + @Transient
  44 + private int startIdx;
  45 +
  46 + // 终点编码
  47 + @JsonIgnore
  48 + private String terminalStationCode;
  49 +
  50 + @Transient
  51 + private int terminalIdx;
  52 +
  53 + // 路段wgs84点位
  54 + @JsonIgnore
  55 + private String points;
  56 +
  57 + public Integer getId() {
  58 + return id;
  59 + }
  60 +
  61 + public void setId(Integer id) {
  62 + this.id = id;
  63 + }
  64 +
  65 + public Integer getLine() {
  66 + return line;
  67 + }
  68 +
  69 + public void setLine(Integer line) {
  70 + this.line = line;
  71 + }
  72 +
  73 + public Integer getVersions() {
  74 + return versions;
  75 + }
  76 +
  77 + public void setVersions(Integer versions) {
  78 + this.versions = versions;
  79 + }
  80 +
  81 + public Integer getDirection() {
  82 + return direction;
  83 + }
  84 +
  85 + public void setDirection(Integer direction) {
  86 + this.direction = direction;
  87 + }
  88 +
  89 + public String getStartStationCode() {
  90 + return startStationCode;
  91 + }
  92 +
  93 + public void setStartStationCode(String startStationCode) {
  94 + this.startStationCode = startStationCode;
  95 + }
  96 +
  97 + public int getStartIdx() {
  98 + return startIdx;
  99 + }
  100 +
  101 + public void setStartIdx(int startIdx) {
  102 + this.startIdx = startIdx;
  103 + }
  104 +
  105 + public String getTerminalStationCode() {
  106 + return terminalStationCode;
  107 + }
  108 +
  109 + public void setTerminalStationCode(String terminalStationCode) {
  110 + this.terminalStationCode = terminalStationCode;
  111 + }
  112 +
  113 + public int getTerminalIdx() {
  114 + return terminalIdx;
  115 + }
  116 +
  117 + public void setTerminalIdx(int terminalIdx) {
  118 + this.terminalIdx = terminalIdx;
  119 + }
  120 +
  121 + public String getPoints() {
  122 + return points;
  123 + }
  124 +
  125 + public void setPoints(String points) {
  126 + this.points = points;
  127 + }
  128 +
  129 + /**
  130 + * 将 points 字段转换为 List<Point> 格式
  131 + * 第一个点位和最后一个点位的 isStation 为 true
  132 + * @return List<Point>
  133 + */
  134 + public List<Point> getList() {
  135 + List<Point> pointList = new ArrayList<>();
  136 + if (points == null || points.isEmpty()) {
  137 + return pointList;
  138 + }
  139 +
  140 + // 按照逗号分割 points 字符串,得到每个点位的字符串
  141 + String[] pointStrings = points.split(",");
  142 + int length = pointStrings.length;
  143 +
  144 + // 遍历每个点位字符串
  145 + for (int i = 0; i < length; i++) {
  146 + String pointString = pointStrings[i].trim();
  147 + if (pointString.isEmpty()) {
  148 + continue;
  149 + }
  150 +
  151 + // 按照空格分割得到经度和纬度
  152 + String[] coords = pointString.split(" ");
  153 + if (coords.length != 2) {
  154 + continue;
  155 + }
  156 +
  157 + try {
  158 + // 创建 Point 对象,设置经纬度
  159 + Point point = new Point();
  160 + point.setLon(Double.parseDouble(coords[0]));
  161 + point.setLat(Double.parseDouble(coords[1]));
  162 +
  163 + // 第一个点位和最后一个点位的 isStation 为 true
  164 + if (i == 0 || i == length - 1) {
  165 + point.setStation(true);
  166 + }
  167 +
  168 + pointList.add(point);
  169 + } catch (NumberFormatException e) {
  170 + // 忽略格式错误的点位
  171 + }
  172 + }
  173 +
  174 + return pointList;
  175 + }
  176 +}
0 177 \ No newline at end of file
... ...
src/main/java/com/bsth/server_rs/base_info/navigation/NavigationRestService.java 0 → 100644
  1 +package com.bsth.server_rs.base_info.navigation;
  2 +
  3 +import com.bsth.entity.Detour;
  4 +import com.bsth.entity.Point;
  5 +import com.bsth.server_rs.base_info.section.buffer.LD_SectionBufferData;
  6 +import com.bsth.server_rs.base_info.section.entity.LD_Section;
  7 +import com.bsth.server_rs.base_info.section.entity.LD_SectionRoute;
  8 +import com.bsth.server_rs.base_info.station.buffer.StationBufferData;
  9 +import com.bsth.server_rs.base_info.station.entity.StationRotue;
  10 +import com.bsth.util.GeoUtils;
  11 +import org.springframework.beans.factory.InitializingBean;
  12 +import org.springframework.beans.factory.annotation.Autowired;
  13 +import org.springframework.jdbc.core.BeanPropertyRowMapper;
  14 +import org.springframework.jdbc.core.JdbcTemplate;
  15 +import org.springframework.scheduling.annotation.EnableScheduling;
  16 +import org.springframework.scheduling.annotation.Scheduled;
  17 +import org.springframework.stereotype.Component;
  18 +
  19 +import javax.ws.rs.GET;
  20 +import javax.ws.rs.Path;
  21 +import javax.ws.rs.PathParam;
  22 +import javax.ws.rs.Produces;
  23 +import javax.ws.rs.core.MediaType;
  24 +import java.util.*;
  25 +import java.util.concurrent.ConcurrentHashMap;
  26 +
  27 +@Component
  28 +@Path("/navigation")
  29 +@Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
  30 +@EnableScheduling
  31 +public class NavigationRestService implements InitializingBean {
  32 +
  33 + @Autowired
  34 + private JdbcTemplate jdbcTemplate;
  35 +
  36 + @Autowired
  37 + private LD_SectionBufferData ldSectionBufferData;
  38 +
  39 + private static Map<String, Integer> line2version = new ConcurrentHashMap<>();
  40 +
  41 + @GET
  42 + @Path("/version/reload")
  43 + @Scheduled(cron = "0 0 * * * *") // 每小时执行一次
  44 + public void reload() {
  45 + Map<String, Integer> line2versionMap = new ConcurrentHashMap<>();
  46 + List<Map<String, Object>> list = jdbcTemplate.queryForList("SELECT line_code,versions FROM `bsth_c_line_versions` where `status` = 1 and now() BETWEEN start_date and end_date");
  47 + for (Map<String, Object> map : list) {
  48 + line2versionMap.put((String) map.get("line_code"), (Integer) map.get("versions"));
  49 + }
  50 + if (!line2versionMap.isEmpty()) {
  51 + line2version = line2versionMap;
  52 + }
  53 + }
  54 +
  55 + /**
  56 + * 获取线路正常路径的点位信息
  57 + * @param lineCode 线路编码
  58 + * @param direction 方向
  59 + * @return 包含线路编码、方向和点位信息的Map
  60 + */
  61 + @GET
  62 + @Path("/normal/{lineCode}/{direction}")
  63 + public Map<String, Object> normal(@PathParam("lineCode") String lineCode, @PathParam("direction") int direction) {
  64 + Map<String, Object> result = new LinkedHashMap<>();
  65 + result.put("lineCode", lineCode);
  66 + result.put("direction", direction);
  67 +
  68 + // 获取路段数据
  69 + Map<String, Collection<LD_SectionRoute>> sectionRoutesMap = ldSectionBufferData.findByLineCode(lineCode);
  70 + if (sectionRoutesMap.isEmpty()) {
  71 + result.put("list", new ArrayList<Point>());
  72 + return result;
  73 + }
  74 +
  75 + // 获取对应方向的路段路由
  76 + Collection<LD_SectionRoute> sectionRoutes = sectionRoutesMap.get(lineCode + "_" + direction);
  77 + if (sectionRoutes == null || sectionRoutes.isEmpty()) {
  78 + result.put("list", new ArrayList<Point>());
  79 + return result;
  80 + }
  81 +
  82 + // 获取站点数据
  83 + Map<String, Collection<StationRotue>> stationRoutesMap = StationBufferData.findRouteByLineCode(lineCode);
  84 + Collection<StationRotue> stationRoutes = stationRoutesMap.get(lineCode + "_" + direction);
  85 + List<StationRotue> stationRotueList = stationRoutes != null ? new ArrayList<>(stationRoutes) : new ArrayList<StationRotue>();
  86 +
  87 + // 创建点位信息列表
  88 + List<Point> points = new ArrayList<>();
  89 +
  90 + // 建立路段到站点的映射
  91 + Map<String, StationRotue> sectionToStationMap = new HashMap<>();
  92 +
  93 + // 遍历站点,为每个站点找最近的路段
  94 + for (StationRotue stationRotue : stationRotueList) {
  95 + if (stationRotue.getStation() == null) {
  96 + continue;
  97 + }
  98 +
  99 + // 创建站点的点位
  100 + Point stationPoint = new Point();
  101 + stationPoint.setLon(stationRotue.getLon());
  102 + stationPoint.setLat(stationRotue.getLat());
  103 +
  104 + // 查找站点最近的路段
  105 + LD_Section nearestSection = findNearestSection(stationRotue, sectionRoutes);
  106 + if (nearestSection != null) {
  107 + // 建立路段到站点的映射
  108 + sectionToStationMap.put(nearestSection.getSectionCode(), stationRotue);
  109 + }
  110 + }
  111 +
  112 + // 遍历路段,处理每个路段
  113 + for (LD_SectionRoute sectionRoute : sectionRoutes) {
  114 + LD_Section section = sectionRoute.getSection();
  115 + if (section == null) {
  116 + continue;
  117 + }
  118 +
  119 + // 检查路段是否有对应的站点
  120 + StationRotue stationRotue = sectionToStationMap.get(section.getSectionCode());
  121 +
  122 + // 创建点位信息
  123 + Point point = createPointFromSection(section, stationRotue);
  124 + if (point != null) {
  125 + points.add(point);
  126 + }
  127 + }
  128 +
  129 + result.put("list", points);
  130 + return result;
  131 + }
  132 +
  133 + /**
  134 + * 查找站点最近的路段
  135 + * @param stationRotue 站点路由
  136 + * @param sectionRoutes 路段路由集合
  137 + * @return 最近的路段
  138 + */
  139 + private LD_Section findNearestSection(StationRotue stationRotue, Collection<LD_SectionRoute> sectionRoutes) {
  140 + if (stationRotue == null || stationRotue.getStation() == null || sectionRoutes == null || sectionRoutes.isEmpty()) {
  141 + return null;
  142 + }
  143 +
  144 + // 创建站点的点位
  145 + Point stationPoint = new Point();
  146 + stationPoint.setLon(stationRotue.getLon());
  147 + stationPoint.setLat(stationRotue.getLat());
  148 +
  149 + LD_Section nearestSection = null;
  150 + double minDistance = Double.MAX_VALUE;
  151 +
  152 + // 遍历路段,找到最近的路段
  153 + for (LD_SectionRoute sectionRoute : sectionRoutes) {
  154 + LD_Section section = sectionRoute.getSection();
  155 + if (section == null) {
  156 + continue;
  157 + }
  158 +
  159 + // 获取路段的所有坐标点
  160 + List<Point> sectionPointList = getSectionPoints(section);
  161 + if (sectionPointList == null || sectionPointList.size() < 2) {
  162 + continue;
  163 + }
  164 +
  165 + // 计算站点到路段折线的最短距离
  166 + double sectionMinDistance = calculateMinDistanceToPolyline(stationPoint, sectionPointList);
  167 +
  168 + // 如果距离更小,更新最近路段
  169 + if (sectionMinDistance < minDistance) {
  170 + minDistance = sectionMinDistance;
  171 + nearestSection = section;
  172 + }
  173 + }
  174 +
  175 + // 直接返回最近的路段,不设置距离阈值
  176 + return nearestSection;
  177 + }
  178 +
  179 + /**
  180 + * 获取路段的所有坐标点
  181 + * @param section 路段
  182 + * @return 路段的所有坐标点
  183 + */
  184 + private List<Point> getSectionPoints(LD_Section section) {
  185 + if (section == null || section.getGsectionVector() == null || section.getGsectionVector().isEmpty()) {
  186 + return null;
  187 + }
  188 +
  189 + List<Point> pointList = new ArrayList<>();
  190 +
  191 + // 解析 WKT 格式的 LINESTRING
  192 + String wkt = section.getGsectionVector();
  193 +
  194 + // 移除 LINESTRING( 前缀和 ) 后缀
  195 + if (wkt.startsWith("LINESTRING(") && wkt.endsWith(")")) {
  196 + String pointsStr = wkt.substring(10, wkt.length() - 1);
  197 +
  198 + // 按照逗号分割得到每个点位的字符串
  199 + String[] points = pointsStr.split(",");
  200 + for (String pointStr : points) {
  201 + String[] coords = pointStr.trim().split(" ");
  202 + if (coords.length != 2) {
  203 + continue;
  204 + }
  205 +
  206 + try {
  207 + Point point = new Point();
  208 + point.setLon(Double.parseDouble(coords[0]));
  209 + point.setLat(Double.parseDouble(coords[1]));
  210 + pointList.add(point);
  211 + } catch (NumberFormatException e) {
  212 + // 忽略格式错误的点位
  213 + }
  214 + }
  215 + }
  216 +
  217 + return pointList;
  218 + }
  219 +
  220 + /**
  221 + * 计算点到折线的最短距离
  222 + * @param point 点
  223 + * @param polyline 折线的坐标点列表
  224 + * @return 点到折线的最短距离
  225 + */
  226 + private double calculateMinDistanceToPolyline(Point point, List<Point> polyline) {
  227 + if (point == null || polyline == null || polyline.size() < 2) {
  228 + return Double.MAX_VALUE;
  229 + }
  230 +
  231 + double minDistance = Double.MAX_VALUE;
  232 +
  233 + // 遍历折线的每一条线段,计算点到线段的距离
  234 + for (int i = 0; i < polyline.size() - 1; i++) {
  235 + Point startPoint = polyline.get(i);
  236 + Point endPoint = polyline.get(i + 1);
  237 +
  238 + // 计算点到线段的距离
  239 + double distance = GeoUtils.getDistanceFromLine(startPoint, endPoint, point);
  240 +
  241 + // 更新最短距离
  242 + if (distance < minDistance) {
  243 + minDistance = distance;
  244 + }
  245 + }
  246 +
  247 + return minDistance;
  248 + }
  249 +
  250 + /**
  251 + * 获取路段的中间点
  252 + * @param section 路段
  253 + * @return 路段的中间点
  254 + */
  255 + private Point getSectionMidPoint(LD_Section section) {
  256 + if (section == null || section.getGsectionVector() == null || section.getGsectionVector().isEmpty()) {
  257 + return null;
  258 + }
  259 +
  260 + // 获取路段的所有坐标点
  261 + List<Point> pointList = getSectionPoints(section);
  262 + if (pointList == null || pointList.size() < 2) {
  263 + return null;
  264 + }
  265 +
  266 + // 计算折线的总长度
  267 + double totalLength = 0;
  268 + List<Double> segmentLengths = new ArrayList<>();
  269 +
  270 + for (int i = 0; i < pointList.size() - 1; i++) {
  271 + Point startPoint = pointList.get(i);
  272 + Point endPoint = pointList.get(i + 1);
  273 + double length = GeoUtils.getDistance(startPoint, endPoint);
  274 + totalLength += length;
  275 + segmentLengths.add(length);
  276 + }
  277 +
  278 + // 如果总长度为0,返回第一个点
  279 + if (totalLength <= 0) {
  280 + return pointList.get(0);
  281 + }
  282 +
  283 + // 找到距离起点为总长度一半的点
  284 + double halfLength = totalLength / 2;
  285 + double currentLength = 0;
  286 +
  287 + for (int i = 0; i < segmentLengths.size(); i++) {
  288 + double segmentLength = segmentLengths.get(i);
  289 + if (currentLength + segmentLength >= halfLength) {
  290 + // 找到包含中间点的线段
  291 + Point startPoint = pointList.get(i);
  292 + Point endPoint = pointList.get(i + 1);
  293 +
  294 + // 计算中间点在线段上的位置
  295 + double ratio = (halfLength - currentLength) / segmentLength;
  296 + double midLon = startPoint.getLon() + (endPoint.getLon() - startPoint.getLon()) * ratio;
  297 + double midLat = startPoint.getLat() + (endPoint.getLat() - startPoint.getLat()) * ratio;
  298 +
  299 + // 创建中间点
  300 + Point midPoint = new Point();
  301 + midPoint.setLon(midLon);
  302 + midPoint.setLat(midLat);
  303 +
  304 + return midPoint;
  305 + }
  306 + currentLength += segmentLength;
  307 + }
  308 +
  309 + // 如果没有找到,返回最后一个点
  310 + return pointList.get(pointList.size() - 1);
  311 + }
  312 +
  313 + /**
  314 + * 根据路段和站点创建点位信息
  315 + * @param section 路段
  316 + * @param station 站点
  317 + * @return 点位信息
  318 + */
  319 + private Point createPointFromSection(LD_Section section, StationRotue station) {
  320 + Point point = new Point();
  321 +
  322 + if (station != null && station.getStation() != null) {
  323 + // 如果有站点,使用站点的坐标
  324 + point.setLon(station.getLon());
  325 + point.setLat(station.getLat());
  326 + point.setStation(true);
  327 + } else {
  328 + // 否则使用路段的中间点坐标
  329 + Point midPoint = getSectionMidPoint(section);
  330 + if (midPoint != null) {
  331 + point.setLon(midPoint.getLon());
  332 + point.setLat(midPoint.getLat());
  333 + point.setStation(false);
  334 + } else {
  335 + return null;
  336 + }
  337 + }
  338 +
  339 + return point;
  340 + }
  341 +
  342 + @GET
  343 + @Path("/detour/{lineCode}/{direction}")
  344 + public List<Detour> detour(@PathParam("lineCode") String lineCode, @PathParam("direction") int direction) {
  345 + Integer version = line2version.get(lineCode);
  346 + if (version == null) {
  347 + version = 1;
  348 + }
  349 + List<Detour> detourList = jdbcTemplate.query("select * from bsth_c_detour where line = ? and versions = ? and direction = ?", new Object[]{ lineCode, version, direction }, BeanPropertyRowMapper.newInstance(Detour.class));
  350 + Map<String, Collection<StationRotue>> map = StationBufferData.findRouteByLineCode(lineCode);
  351 + if (map.isEmpty()) {
  352 + return new ArrayList<>();
  353 + }
  354 + Collection<StationRotue> stationRotueCollection = map.get(String.format("%s_%d", lineCode, direction));
  355 +
  356 + // 处理 detourList,将 startStationCode 和 terminalStationCode 替换为对应的索引值+1
  357 + processDetourStations(detourList, stationRotueCollection);
  358 +
  359 + // 过滤掉 terminalIdx 不大于 startIdx 的对象
  360 + List<Detour> filteredDetourList = new ArrayList<>();
  361 + for (Detour detour : detourList) {
  362 + if (detour.getTerminalIdx() > detour.getStartIdx()) {
  363 + filteredDetourList.add(detour);
  364 + }
  365 + }
  366 +
  367 + return filteredDetourList;
  368 + }
  369 +
  370 + /**
  371 + * 处理绕改道站点,将站点编码替换为对应的索引值+1
  372 + * @param detourList 绕改道列表
  373 + * @param stationRotueCollection 站点路由集合
  374 + */
  375 + private void processDetourStations(List<Detour> detourList, Collection<StationRotue> stationRotueCollection) {
  376 + if (detourList == null || detourList.isEmpty() || stationRotueCollection == null || stationRotueCollection.isEmpty()) {
  377 + return;
  378 + }
  379 +
  380 + // 将 stationRotueCollection 转换为列表,以便获取索引
  381 + List<StationRotue> stationRotueList = new ArrayList<>(stationRotueCollection);
  382 +
  383 + // 遍历 detourList,处理每个绕改道对象
  384 + for (Detour detour : detourList) {
  385 + String startStationCode = detour.getStartStationCode();
  386 + String terminalStationCode = detour.getTerminalStationCode();
  387 +
  388 + // 查找起点站的索引
  389 + for (int i = 0; i < stationRotueList.size(); i++) {
  390 + StationRotue stationRotue = stationRotueList.get(i);
  391 + if (startStationCode != null && startStationCode.equals(stationRotue.getStationCode())) {
  392 + detour.setStartIdx(i + 1); // 索引值+1
  393 + break;
  394 + }
  395 + }
  396 +
  397 + // 查找终点站的索引
  398 + for (int i = detour.getStartIdx(); i < stationRotueList.size(); i++) {
  399 + StationRotue stationRotue = stationRotueList.get(i);
  400 + if (terminalStationCode != null && terminalStationCode.equals(stationRotue.getStationCode())) {
  401 + detour.setTerminalIdx(i + 1); // 索引值+1
  402 + break;
  403 + }
  404 + }
  405 + }
  406 + }
  407 +
  408 + @Override
  409 + public void afterPropertiesSet() throws Exception {
  410 + reload();
  411 + }
  412 +}
... ...
src/main/java/com/bsth/util/GeoUtils.java 0 → 100644
  1 +package com.bsth.util;
  2 +
  3 +import com.bsth.entity.Point;
  4 +
  5 +/**
  6 + * Created by panzhao on 2016/12/23.
  7 + */
  8 +public class GeoUtils {
  9 +
  10 + private final static double EARTH_RADIUS = 6378137;
  11 +
  12 + public static double getDistance(Point p1, Point p2) {
  13 + double lng1 = getLoop(p1.getLon(), -180, 180), lat1 = getRange(
  14 + p1.getLat(), -74, 74);
  15 + double lng2 = getLoop(p2.getLon(), -180, 180), lat2 = getRange(
  16 + p2.getLat(), -74, 74);
  17 +
  18 + double x1, x2, y1, y2;
  19 + x1 = degreeToRad(lng1);
  20 + y1 = degreeToRad(lat1);
  21 + x2 = degreeToRad(lng2);
  22 + y2 = degreeToRad(lat2);
  23 + return EARTH_RADIUS
  24 + * Math.acos((Math.sin(y1) * Math.sin(y2) + Math.cos(y1)
  25 + * Math.cos(y2) * Math.cos(x2 - x1)));
  26 + }
  27 +
  28 + private static double getLoop(double v, double a, double b) {
  29 + while (v > b) {
  30 + v -= b - a;
  31 + }
  32 + while (v < a) {
  33 + v += b - a;
  34 + }
  35 + return v;
  36 + }
  37 +
  38 + private static double getRange(double v, double a, double b) {
  39 + v = Math.min(Math.max(v, a), b);
  40 + return v;
  41 + }
  42 +
  43 + private static double degreeToRad(double degree) {
  44 + return Math.PI * degree / 180;
  45 + }
  46 +
  47 + /**
  48 + * 计算点 到 线的距离
  49 + * @param line
  50 + * @param p
  51 + * @return
  52 + */
  53 + public static double getDistanceFromLine(Point s, Point e, Point p){
  54 + double d1 = getDistance(s, p);
  55 + double d2 = getDistance(p, e);
  56 + double d3 = getDistance(s, e);
  57 + double distance = 0;
  58 +
  59 + double alpha = Math.acos((d1*d1 + d3*d3 - d2*d2)/(2*d1*d3));
  60 + double beta = Math.acos((d2*d2 + d3*d3 - d1*d1)/(2*d2*d3));
  61 +
  62 + if(alpha>Math.PI/2) {
  63 + distance = d1;
  64 + }
  65 + else if(beta > Math.PI/2) {
  66 + distance = d2;
  67 + }
  68 + else {
  69 + distance = Math.sin(alpha) * d1;
  70 + }
  71 + return distance;
  72 + }
  73 +}
... ...