Commit 819d87fa authored by zhoushiguang's avatar zhoushiguang

冲突点计算任务

parent afbcf6c6
......@@ -2,11 +2,11 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<!--<parent>
<artifactId>wj-platform</artifactId>
<groupId>com.wanji</groupId>
<version>1.0</version>
</parent>-->
<!-- <parent>-->
<!-- <artifactId>wj-datacenter-platform</artifactId>-->
<!-- <groupId>net.wanji</groupId>-->
<!-- <version>1.0-SNAPSHOT</version>-->
<!-- </parent>-->
<modelVersion>4.0.0</modelVersion>
<groupId>com.wanji</groupId>
......@@ -21,9 +21,9 @@
<elasticsearch.version>7.10.1</elasticsearch.version>
<es.client.version>7.10.1</es.client.version>
<!-- jar包名尾部标识 -->
<jar.tail>all</jar.tail>
<!--<jar.tail>all</jar.tail>-->
<!--<jar.tail>batch-track</jar.tail>-->
<!--<jar.tail>export</jar.tail>-->
<jar.tail>export</jar.tail>
<!--<jar.tail>export</jar.tail>-->
<!--<jar.tail>monitor</jar.tail>-->
</properties>
......@@ -59,32 +59,32 @@
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>4.1.4.RELEASE</version>
<version>5.0.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.1.4.RELEASE</version>
<version>5.0.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>4.1.4.RELEASE</version>
<version>5.0.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.1.4.RELEASE</version>
<version>5.0.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>4.1.4.RELEASE</version>
<version>5.0.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.1.4.RELEASE</version>
<version>5.0.7.RELEASE</version>
</dependency>
<dependency>
<groupId>javax.transaction</groupId>
......@@ -214,7 +214,7 @@
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<artifactId>slf4j-reload4j</artifactId>
<version>1.7.36</version>
<scope>runtime</scope>
</dependency>
......
package com.wanji.indicators.base.bean;
/**
* github地址: https://github.com/intsmaze
* 博客地址:https://www.cnblogs.com/intsmaze/
* 出版书籍《深入理解Flink核心设计与实践原理》
*
* @auther: intsmaze(刘洋)
* @date: 2020/10/15 18:33
*/
public class FlowData {
private String uuid;
private String subTestItem;
private String billNumber;
private String barcode;
private String flowName;
private String flowStatus;
public String getFlowStatus() {
return flowStatus;
}
public void setFlowStatus(String flowStatus) {
this.flowStatus = flowStatus;
}
public String getUuid() {
return uuid;
}
public void setUuid(String uuid) {
this.uuid = uuid;
}
public String getSubTestItem() {
return subTestItem;
}
public void setSubTestItem(String subTestItem) {
this.subTestItem = subTestItem;
}
public String getBillNumber() {
return billNumber;
}
public void setBillNumber(String billNumber) {
this.billNumber = billNumber;
}
public String getBarcode() {
return barcode;
}
public void setBarcode(String barcode) {
this.barcode = barcode;
}
public String getFlowName() {
return flowName;
}
public void setFlowName(String flowName) {
this.flowName = flowName;
}
@Override
public String toString() {
return "FlowData{" +
"uuid='" + uuid + '\'' +
", subTestItem='" + subTestItem + '\'' +
", billNumber='" + billNumber + '\'' +
", barcode='" + barcode + '\'' +
", flowName='" + flowName + '\'' +
", flowStatus='" + flowStatus + '\'' +
'}';
}
}
package com.wanji.indicators.base.bean;
import java.sql.Timestamp;
/**
* github地址: https://github.com/intsmaze
* 博客地址:https://www.cnblogs.com/intsmaze/
* 出版书籍《深入理解Flink核心设计与实践原理》
*
* @auther: intsmaze(刘洋)
* @date: 2020/10/15 18:33
*/
public class MainData {
private String subTestItem;
private String billNumber;
private String barcode;
private String flowName;
private Timestamp testTime;
private int seqId;
private int stepNumber;
private String stepType;
public String getSubTestItem() {
return subTestItem;
}
public void setSubTestItem(String subTestItem) {
this.subTestItem = subTestItem;
}
public String getBillNumber() {
return billNumber;
}
public void setBillNumber(String billNumber) {
this.billNumber = billNumber;
}
public String getBarcode() {
return barcode;
}
public void setBarcode(String barcode) {
this.barcode = barcode;
}
public String getFlowName() {
return flowName;
}
public void setFlowName(String flowName) {
this.flowName = flowName;
}
public Timestamp getTestTime() {
return testTime;
}
public void setTestTime(Timestamp testTime) {
this.testTime = testTime;
}
public int getSeqId() {
return seqId;
}
public void setSeqId(int seqId) {
this.seqId = seqId;
}
public int getStepNumber() {
return stepNumber;
}
public void setStepNumber(int stepNumber) {
this.stepNumber = stepNumber;
}
public String getStepType() {
return stepType;
}
public void setStepType(String stepType) {
this.stepType = stepType;
}
}
package com.wanji.indicators.base.bean;
/**
* github地址: https://github.com/intsmaze
* 博客地址:https://www.cnblogs.com/intsmaze/
* 出版书籍《深入理解Flink核心设计与实践原理》
*
* @auther: intsmaze(刘洋)
* @date: 2020/10/15 18:33
*/
public class ResultBean {
private String flowId;
private int cycleNumber;
private long total;
private int stepNumber;
private String stepType;
public String getFlowId() {
return flowId;
}
public void setFlowId(String flowId) {
this.flowId = flowId;
}
public int getCycleNumber() {
return cycleNumber;
}
public void setCycleNumber(int cycleNumber) {
this.cycleNumber = cycleNumber;
}
public long getTotal() {
return total;
}
public void setTotal(long total) {
this.total = total;
}
public int getStepNumber() {
return stepNumber;
}
public void setStepNumber(int stepNumber) {
this.stepNumber = stepNumber;
}
public String getStepType() {
return stepType;
}
public void setStepType(String stepType) {
this.stepType = stepType;
}
@Override
public String toString() {
return "ResultBean{" +
"flowId='" + flowId + '\'' +
", cycleNumber=" + cycleNumber +
", total=" + total +
", stepNumber=" + stepNumber +
", stepType='" + stepType + '\'' +
'}';
}
}
package com.wanji.indicators.base.bean;
import java.sql.Timestamp;
/**
* github地址: https://github.com/intsmaze
* 博客地址:https://www.cnblogs.com/intsmaze/
* 出版书籍《深入理解Flink核心设计与实践原理》
*
* @auther: intsmaze(刘洋)
* @date: 2020/10/15 18:33
*/
public class SourceData {
/**
* 是否触发执行的标志
*/
private String flag;
private String uuid;
/**
* sqlClient也用的这个字段,RowNumberBean 中进行比较,字段类型也是它
*/
private Timestamp testTime;
private int seqId;
private int stepNumber;
private String stepType;
private int cycleNumber;
private int batchNumber;
private String flowId;
private String threadName;
/**
* 用于eventtime
*/
private Timestamp receiveTime;
public SourceData()
{}
public SourceData(String flag, String uuid, Timestamp testTime, int seqId, int stepNumber, String stepType, int cycleNumber,
int batchNumber, String flowId, String threadName, Timestamp receiveTime) {
this.flag = flag;
this.uuid = uuid;
this.testTime = testTime;
this.seqId = seqId;
this.stepNumber = stepNumber;
this.stepType = stepType;
this.cycleNumber = cycleNumber;
this.batchNumber = batchNumber;
this.flowId = flowId;
this.threadName = threadName;
this.receiveTime = receiveTime;
}
public String getFlag() {
return flag;
}
public void setFlag(String flag) {
this.flag = flag;
}
public String getUuid() {
return uuid;
}
public void setUuid(String uuid) {
this.uuid = uuid;
}
public Timestamp getTestTime() {
return testTime;
}
public void setTestTime(Timestamp testTime) {
this.testTime = testTime;
}
public int getSeqId() {
return seqId;
}
public void setSeqId(int seqId) {
this.seqId = seqId;
}
public int getStepNumber() {
return stepNumber;
}
public void setStepNumber(int stepNumber) {
this.stepNumber = stepNumber;
}
public String getStepType() {
return stepType;
}
public void setStepType(String stepType) {
this.stepType = stepType;
}
public int getCycleNumber() {
return cycleNumber;
}
public void setCycleNumber(int cycleNumber) {
this.cycleNumber = cycleNumber;
}
public int getBatchNumber() {
return batchNumber;
}
public void setBatchNumber(int batchNumber) {
batchNumber = batchNumber;
}
public String getFlowId() {
return flowId;
}
public void setFlowId(String flowId) {
this.flowId = flowId;
}
public String getThreadName() {
return threadName;
}
public void setThreadName(String threadName) {
this.threadName = threadName;
}
public Timestamp getReceiveTime() {
return receiveTime;
}
public void setReceiveTime(Timestamp receiveTime) {
this.receiveTime = receiveTime;
}
@Override
public String toString() {
return "SourceData{" +
"flowId='" + flowId + '\'' +
", cycleNumber=" + cycleNumber +
", flag='" + flag + '\'' +
", seqId=" + seqId +
", stepNumber='" + stepNumber + '\'' +
", stepType='" + stepType + '\'' +
'}';
}
}
package com.wanji.indicators.base.env;
import com.google.common.base.Charsets;
import com.google.common.base.Throwables;
import com.google.common.io.Resources;
import org.apache.flink.configuration.Configuration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.Resource;
import java.net.URL;
/**
* github地址: https://github.com/intsmaze
* 博客地址:https://www.cnblogs.com/intsmaze/
* 出版书籍《深入理解Flink核心设计与实践原理》
*
* @auther: intsmaze(刘洋)
* @date: 2020/10/15 18:33
*/
public class BeanFactory extends DefaultListableBeanFactory {
public static Logger LOG = LoggerFactory.getLogger(BeanFactory.class);
public static final String SPRING_BEAN_FACTORY_XML = "springframework.bean.factory.xml";
public static final String SPRING_BEAN_FACTORY_NAME = "springframework.bean.factory.name";
public static final String DUBBO_SPRING_BEAN_FACTORY_NAME = "dubbo.springframework.bean.factory.name";
private static BeanFactory instance;
public static BeanFactory getInstance() {
return instance;
}
public static void setInstance(BeanFactory instance) {
BeanFactory.instance = instance;
}
private transient final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);
private String xml;
/**
* github地址: https://github.com/intsmaze
* 博客地址:https://www.cnblogs.com/intsmaze/
* 出版书籍《深入理解Flink核心设计与实践原理》
*
* @auther: intsmaze(刘洋)
* @date: 2020/10/15 18:33
*/
public BeanFactory(String location) {
super();
try {
Resource resource = reader.getResourceLoader().getResource(location);
URL url = resource.getURL();
this.xml = Resources.toString(url, Charsets.UTF_8);
this.reader.setValidating(false);
this.reader.loadBeanDefinitions(resource);
} catch (Exception e) {
throw Throwables.propagate(e);
}
}
/**
* github地址: https://github.com/intsmaze
* 博客地址:https://www.cnblogs.com/intsmaze/
* 出版书籍《深入理解Flink核心设计与实践原理》
*
* @auther: intsmaze(刘洋)
* @date: 2020/10/15 18:33
*/
public BeanFactory(Configuration stormConf) {
this.xml = stormConf.getString(SPRING_BEAN_FACTORY_XML,null);
System.out.println("----->>>>> xml content is :"+xml);
LOG.info("----->>>>> xml content is :{}"+xml);
this.reader.setValidating(false);
this.reader.loadBeanDefinitions(new ByteArrayResource(xml.getBytes(Charsets.UTF_8)));
}
/**
* github地址: https://github.com/intsmaze
* 博客地址:https://www.cnblogs.com/intsmaze/
* 出版书籍《深入理解Flink核心设计与实践原理》
*
* @auther: intsmaze(刘洋)
* @date: 2020/10/15 18:33
*/
public static ApplicationContext getBeanFactory(Configuration globalJobParameters) {
String xmlName = globalJobParameters.getString(BeanFactory.SPRING_BEAN_FACTORY_NAME, null);
System.out.println("xmlName is :"+xmlName);
ApplicationContext beanConf = new ClassPathXmlApplicationContext(xmlName);
return beanConf;
}
/**
* github地址: https://github.com/intsmaze
* 博客地址:https://www.cnblogs.com/intsmaze/
* 出版书籍《深入理解Flink核心设计与实践原理》
*
* @auther: intsmaze(刘洋)
* @date: 2020/10/15 18:33
*/
public static ApplicationContext getDubboBeanFactory(Configuration globalJobParameters) {
String xmlName = globalJobParameters.getString(BeanFactory.DUBBO_SPRING_BEAN_FACTORY_NAME, null);
System.out.println("xmlName is :"+xmlName);
ApplicationContext beanConf = new ClassPathXmlApplicationContext(xmlName);
return beanConf;
}
/**
* github地址: https://github.com/intsmaze
* 博客地址:https://www.cnblogs.com/intsmaze/
* 出版书籍《深入理解Flink核心设计与实践原理》
*
* @auther: intsmaze(刘洋)
* @date: 2020/10/15 18:33
*/
public String getXml() {
return xml;
}
}
package com.wanji.indicators.base.jdbc;//package com.intsmaze.flink.base.jdbc;
//
//import org.springframework.jdbc.core.JdbcTemplate;
//
//import java.util.List;
//import java.util.Map;
//
//
///**
// * github地址: https://github.com/intsmaze
// * 博客地址:https://www.cnblogs.com/intsmaze/
// * 出版书籍《深入理解Flink核心设计与实践原理》
// *
// * @auther: intsmaze(刘洋)
// * @date: 2020/10/15 18:33
// */
//public class VariableJdbc {
//
// private JdbcTemplate jdbcTemplate;
//
// public JdbcTemplate getJdbcTemplate() {
// return jdbcTemplate;
// }
//
// public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
// this.jdbcTemplate = jdbcTemplate;
// }
//
// /**
// * github地址: https://github.com/intsmaze
// * 博客地址:https://www.cnblogs.com/intsmaze/
// * 出版书籍《深入理解Flink核心设计与实践原理》
// *
// * @auther: intsmaze(刘洋)
// * @date: 2020/10/15 18:33
// */
// public List<Map<String, Object>> findVariable() {
// String sql = "select name,value from variable ";
// List<Map<String, Object>> variableList = jdbcTemplate.queryForList(sql);
// return variableList;
// }
//
//}
package com.wanji.indicators.base.thread;//package com.intsmaze.flink.base.thread;
//
//import com.google.common.collect.Maps;
//import com.intsmaze.flink.base.jdbc.VariableJdbc;
//import org.slf4j.Logger;
//import org.slf4j.LoggerFactory;
//
//import java.util.List;
//import java.util.Map;
//import java.util.concurrent.ConcurrentMap;
//import java.util.concurrent.TimeUnit;
//
///**
// * github地址: https://github.com/intsmaze
// * 博客地址:https://www.cnblogs.com/intsmaze/
// * 出版书籍《深入理解Flink核心设计与实践原理》
// *
// * @auther: intsmaze(刘洋)
// * @date: 2020/10/15 18:33
// */
//public class SwitchThread {
//
// public static String isSleep = "isSleep";
//
// private final Logger logger = LoggerFactory.getLogger(this.getClass());
//
// public static ConcurrentMap<String, Object> activityConfigs = Maps.newConcurrentMap();
//
// private static volatile boolean inited = false;
//
// private VariableJdbc variableJdbc;
//
// private static volatile Thread updateThread;
//
// /**
// * github地址: https://github.com/intsmaze
// * 博客地址:https://www.cnblogs.com/intsmaze/
// * 出版书籍《深入理解Flink核心设计与实践原理》
// *
// * @auther: intsmaze(刘洋)
// * @date: 2020/10/15 18:33
// */
// public void init() {
// synchronized (SwitchThread.class) {
// if (inited) {
// return;
// }
// logger.info("初始化配置数据......");
// initVariableDictTry();
// inited = true;
// start();
// }
// }
//
// /**
// * github地址: https://github.com/intsmaze
// * 博客地址:https://www.cnblogs.com/intsmaze/
// * 出版书籍《深入理解Flink核心设计与实践原理》
// *
// * @auther: intsmaze(刘洋)
// * @date: 2020/10/15 18:33
// */
// private void initVariableDictTry() {
// List<Map<String, Object>> variableList = variableJdbc.findVariable();
// for (int i = 0; i < variableList.size(); i++) {
// Map<String, Object> stringObjectMap = variableList.get(i);
// String name = (String) stringObjectMap.get("name");
// String value = (String) stringObjectMap.get("value");
// activityConfigs.put(name, value);
// }
// }
//
// /**
// * github地址: https://github.com/intsmaze
// * 博客地址:https://www.cnblogs.com/intsmaze/
// * 出版书籍《深入理解Flink核心设计与实践原理》
// *
// * @auther: intsmaze(刘洋)
// * @date: 2020/10/15 18:33
// */
// public void start() {
// synchronized (SwitchThread.class) {
// if (updateThread != null) {
// return;
// }
// updateThread = new UpdateThread();
// updateThread.start();
// }
// }
//
// /**
// * github地址: https://github.com/intsmaze
// * 博客地址:https://www.cnblogs.com/intsmaze/
// * 出版书籍《深入理解Flink核心设计与实践原理》
// *
// * @auther: intsmaze(刘洋)
// * @date: 2020/10/15 18:33
// */
// private class UpdateThread extends Thread {
// /**
// * github地址: https://github.com/intsmaze
// * 博客地址:https://www.cnblogs.com/intsmaze/
// * 出版书籍《深入理解Flink核心设计与实践原理》
// *
// * @auther: intsmaze(刘洋)
// * @date: 2020/10/15 18:33
// */
// @Override
// public void run() {
// while (true) {
// try {
// TimeUnit.MINUTES.sleep(1);
// } catch (InterruptedException e1) {
// }
// logger.info("更新配置数据......");
// try {
// initVariableDictTry();
// } catch (Exception e) {
// logger.error("", e);
// }
// }
// }
// }
//
// public VariableJdbc getVariableJdbc() {
// return variableJdbc;
// }
//
// public void setVariableJdbc(VariableJdbc variableJdbc) {
// this.variableJdbc = variableJdbc;
// }
//}
package com.wanji.indicators.base.util;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
/**
* github地址: https://github.com/intsmaze
* 博客地址:https://www.cnblogs.com/intsmaze/
* 出版书籍《深入理解Flink核心设计与实践原理》
*
* @auther: intsmaze(刘洋)
* @date: 2020/10/15 18:33
*/
public class PropertiesUtils {
/**
* github地址: https://github.com/intsmaze
* 博客地址:https://www.cnblogs.com/intsmaze/
* 出版书籍《深入理解Flink核心设计与实践原理》
*
* @auther: intsmaze(刘洋)
* @date: 2020/10/15 18:33
*/
public static Properties getProperties(String path) throws IOException {
InputStream ips = PropertiesUtils.class
.getClassLoader()
.getResourceAsStream(path);
Properties props = new Properties();
props.load(ips);
ips.close();
return props;
}
}
package com.wanji.indicators.constant;
import java.util.HashMap;
import java.util.Map;
public class Constant {
public static final String EMPTY="EMPTY";
//机动车类型集合,逗号分割
public static final String MOTOR_TYPES= "1,2,3,7,8,10,11,12,13,15";
public static final String MOTOR_TYPES = "1,2,3,7,8,10,11,12,13,15";
public static final String AREA_REALTIME_INDICATOR= "AREA_REALTIME_INDICATOR";
public static final String AREA_REALTIME_INDICATOR = "AREA_REALTIME_INDICATOR";
public static final String HASH_KEY_TRAVEL_DATA = "TRAVEL_DATA";
public static final String HASH_KEY_AREA_FREE_FLOW_SPEED = "AREA_FREE_FLOW_SPEED";
public static final String HASH_KEY_AREA_MAX_QUEUE_LENGTH = "AREA_MAX_QUEUE_LENGTH";
public static final String RID_MARK = "RID_XXXXXXXXXXXXXXXXXXX";
public static final String RID_MARK_LANE = "LANE_XXXXXXXXXXXXXXXXXXXXXXX";
public static final String CONSUL_EVENT_PATH = "flink/runtime";
public static final String CONSUL_EVENT_SETTINGS = "flink/safety";
public static final String CONSUL_EVENT_TEMPLATE = "template";
public static final String CONSUL_EVENT_PARAM_SET = "paramSet";
public static final String CONSUL_EVENT_AREA_SET = "areaSet";
/**
* 开关 开
*/
public static final String ON = "ON";
/**
* 开关 关
*/
public static final String OFF = "OFF";
/**
* 离线计算 windows 默认工作目录
*/
public static String PATH_WINDOWS = "D:\\flink\\workspace\\";
/**
* 离线计算 linux 默认工作目录
*/
public static String PATH_LINUX = "/opt/flink/work/";//"/data/flink/workspace/";
/**
* 区域划分代码 - 斑马线上
*/
public static final int ZEBRA_CROSSING = 0;
/**
* 区域划分代码 - 路口中央
*/
public static final int CROSSING_CENTER = 1;
/**
* 区域划分代码 - 路口出口
*/
public static final int CROSSING_EXPORT = 2;
/**
* 轨迹数据在路口内
*/
public static int CROSSING = 1;
/**
* 入侵结果
*/
public static final String SAVE_PATH = "/invade/";
/**
* 事故-目标车辆
*/
public static final String TARGET_VEHICLE = "目标车辆";
/**
* 事故相关
*/
public static final String SUSPECTED_COLLISION = "疑似碰撞";
public static final String REAR_END_COLLISION = "疑似追尾";
public static final String SIDE_IMPACT = "疑似侧碰";
public static final String SCRATCH = "疑似刮蹭";
public static final String AND = " 与 ";
public static final String SINGLE_CAR_ACCIDENT = "疑似单车事故: ";
public static final String MULTI_CAR_ACCIDENT = "疑似多车事故: ";
public static final String TRAJECTORY_ANALYSIS_A = "根据轨迹分析,现场仅 ";
public static final String TRAJECTORY_ANALYSIS_B = " 一辆机动车涉及事故。";
public static final String CAUSE_OF_TROUBLE_A = " 从相同方向进入路口行驶,发生事故。";
public static final String CAUSE_OF_TROUBLE_B = " 从不同方向进入路口,行驶路线发生冲突,导致事故。";
public static final String CAUSE_OF_TROUBLE_C = " 行驶路线发生冲突,导致事故。";
public static final String RESPONSIBILITY_A = " 责任占比较高(仅供参考)";
public static final String RESPONSIBILITY_B = " 行车轨迹复杂,请参考现场视频判定责任方。";
public static final String POSITION = " 为后车 。";
public static final String EN_SUSPECTED_COLLISION = "Suspected collision";//疑似碰撞
public static final String EN_REAR_END_COLLISION = "Suspected rear end collision";//疑似追尾
public static final String EN_SIDE_IMPACT = "Suspected side impact";//疑似侧碰
public static final String EN_SCRATCH = "Suspected scraping";//疑似刮蹭
public static final String EN_AND = " and ";
/**
* 疑似单车事故
*/
public static final String EN_SINGLE_CAR_ACCIDENT = "Suspected vehicle accident: ";
/**
* 疑似多车事故
*/
public static final String EN_MULTI_CAR_ACCIDENT = "Suspected multi-vehicle accident: ";
/**
* 根据轨迹分析,现场仅一辆机动车涉及事故
*/
public static final String EN_TRAJECTORY_ANALYSIS_A = "According to the trajectory analysis, only one vehicle was involved in the accident ";
public static final String EN_TRAJECTORY_ANALYSIS_B = Constant.EMPTY_STRING;
/**
* aaa 与 bbb 从相同方向进入路口行驶,发生事故。
*/
public static final String EN_CAUSE_OF_TROUBLE_A = " driving from the same direction into the cross, causing an accident.";
/**
* aaa 与 bbb 从不同方向进入路口,行驶路线发生冲突,导致事故。
*/
public static final String EN_CAUSE_OF_TROUBLE_B = " when entering the cross from different directions, the driving route conflicts, resulting in accidents.";
public static final String EN_CAUSE_OF_TROUBLE_C = "the driving route conflicts, resulting in accidents.";
/**
* bbb 责任占比较高(仅供参考)
*/
public static final String EN_RESPONSIBILITY_A = " has a high proportion of responsibility (for reference only)";
/**
* 行车轨迹复杂,请参考现场视频判定责任方。
*/
public static final String EN_RESPONSIBILITY_B = " The driving track is complex, please refer to the scene video to determine the responsible party.";
/**
* bbb 为后车 。
*/
public static final String EN_POSITION = " is rear car.";
/**
* 任务黑名单配置
*/
public static final String JOB_BLACK_LIST = "JOB_BLACK_LIST";
/**
* kafka服务地址
*/
public static final String KAFKA_BOOTSTRAP_SERVERS = "KAFKA_BOOTSTRAP_SERVERS";
/**
* 首页数据保存时间 - redis TTL
*/
public static final String REDIS_ACCIDENT_TTL = "REDIS_ACCIDENT_TTL";
/**
* 常用分隔符
*/
public static final String MARK = "-";
/**
* 常用分隔符
*/
public static final String ADD = "+";
/**
* 常用分隔符
*/
public static final String SPACE = " ";
/**
* 常用分隔符
*/
public static final String COMMA = ",";
/**
* 常用分隔符 分号
*/
public static final String SEMICOLON = ";";
/**
* 常用分隔符 冒号
*/
public static final String COLON = ":";
/**
* 空字符串
*/
public static final String EMPTY_STRING = "";
/**
* 数据类型字典 机动车=1 非机动车=2 行人=3
*/
public static final int VEHICLE = 1;
public static final int NON_VEHICLE = 2;
public static final int PEOPLE = 3;
/**
* 事件开启状态 1开启 0关闭
*/
public static final int OPEN = 1;
/**
* 车道功能 - 高精转向字典
*/
public static final Map<String, String> mapGJ = new HashMap<>();
/**
* 中英转换 - 高精转向字典
*/
public static final Map<String, String> mapGJEn = new HashMap<>();
/**
* 车道功能 - 转向字典
*/
public static final Map<String, String> mapTurn = new HashMap<>();
/**
* rid - 行车方向字典
*/
public static final Map<String, String> mapRidDir = new HashMap<>();
/**
* 行车方向字典 - rid
*/
public static final Map<String, String> mapDirRid = new HashMap<>();
/**
* 事故汉转英字典
*/
public static final Map<String, String> mapAccident = new HashMap<>();
public static final String LEFT_TURN = "左转";
public static final String STRAIGHT_LINE = "直行";
public static final String RIGHT_TURN = "右转";
public static final String TURN_AROUND = "掉头";
/**
* 地理方向代码
*/
public static final String E = "东";
public static final String W = "西";
public static final String S = "南";
public static final String N = "北";
public static final String EN = "东北";
public static final String WN = "西北";
public static final String ES = "东南";
public static final String WS = "西南";
/**
* 转向代码
*/
public static final String LEFT_TURN_CODE = "1";
public static final String STRAIGHT_LINE_CODE = "2";
public static final String RIGHT_TURN_CODE = "3";
public static final String TURN_AROUND_CODE = "4";
/**
* 信号灯态代码
*/
public static final String RED = "R";
public static final String YELLOW = "Y";
public static final String GREEN = "G";
public static final String SG = "SG";
public static final String WGBD = "WGBD";
public static final String CTD = "CTD";
public static final String BACDXS = "BACDXS";
public static final String WFCS = "WFCS";
public static final String YDYC = "YDYC";
public static final String SJYS = "SJYS";
public static final String DHCYZ = "DHCYZ";
public static final String NX = "NX";
//机动车灯组标识
public static final String MOTOR_LIGHT = "motor";
//人行灯组标识
public static final String PED_LIGHT = "ped";
/*
* 高精转向代码 0右转 1直行 2左转
*/
static {
//左转
mapGJ.put("1", LEFT_TURN);
//直行
mapGJ.put("2", STRAIGHT_LINE);
//右转
mapGJ.put("3", RIGHT_TURN);
//掉头
mapGJ.put("4", TURN_AROUND);
//左转
mapTurn.put("1", LEFT_TURN);
//直行
mapTurn.put("2", STRAIGHT_LINE);
//右转
mapTurn.put("3", RIGHT_TURN);
//掉头
mapTurn.put("4", TURN_AROUND);
mapGJEn.put(LEFT_TURN, "turn left");
mapGJEn.put(STRAIGHT_LINE, "straight ahead");
mapGJEn.put(RIGHT_TURN, "turn right");
mapGJEn.put(TURN_AROUND, "turn around");
//rid行车方向
//南向北
mapRidDir.put("1", "南向北");
//西向东
mapRidDir.put("2", "西向东");
//北向南
mapRidDir.put("3", "北向南");
//东向西
mapRidDir.put("4", "东向西");
//地理方向代码
mapDirRid.put(S, "1");
mapDirRid.put(W, "2");
mapDirRid.put(N, "3");
mapDirRid.put(E, "4");
//事故汉转英
mapAccident.put(SUSPECTED_COLLISION, EN_SUSPECTED_COLLISION);
mapAccident.put(REAR_END_COLLISION, EN_REAR_END_COLLISION);
mapAccident.put(SIDE_IMPACT, EN_SIDE_IMPACT);
mapAccident.put(SCRATCH, EN_SCRATCH);
mapAccident.put(POSITION, EN_POSITION);
mapAccident.put(RESPONSIBILITY_A, EN_RESPONSIBILITY_A);
mapAccident.put(RESPONSIBILITY_B, EN_RESPONSIBILITY_B);
mapAccident.put(CAUSE_OF_TROUBLE_A, EN_CAUSE_OF_TROUBLE_A);
mapAccident.put(CAUSE_OF_TROUBLE_B, EN_CAUSE_OF_TROUBLE_B);
mapAccident.put(CAUSE_OF_TROUBLE_C, EN_CAUSE_OF_TROUBLE_C);
}
}
......@@ -12,7 +12,6 @@ import com.baomidou.mybatisplus.extension.activerecord.Model;
@Data
@EqualsAndHashCode(callSuper=false)
@TableName("t_base_rid_info")
public class BaseRidInfo extends Model<BaseRidInfo> {
private static final long serialVersionUID = 1L;
......
package com.wanji.indicators.task.conflictpoint;
package com.wanji.indicators.event.cross.conflictpoint;
import com.alibaba.fastjson.JSONObject;
import com.wanji.indicators.model.BaseEventResultModel;
import com.wanji.indicators.model.ConflictPointModelBase;
import com.wanji.indicators.model.EventCross;
import com.wanji.indicators.model.FrameModel;
import com.wanji.indicators.source.WaitingAreaSource;
import com.wanji.indicators.task.conflictpoint.func.*;
import com.wanji.indicators.event.cross.conflictpoint.func.*;
import com.wanji.indicators.model.*;
import com.wanji.indicators.model.event.confilct.EventCross;
import com.wanji.indicators.sink.EventFileSink;
import com.wanji.indicators.source.LaneInfoSource;
import com.wanji.indicators.util.PropertiesHelper;
import org.apache.flink.api.common.functions.FlatMapFunction;
import org.apache.flink.api.common.serialization.SimpleStringSchema;
......@@ -48,16 +47,22 @@ public class ConflictEventMain implements Serializable {
this.isDebug = isDebug;
}
public static ConflictEventMain init(StreamExecutionEnvironment env, String path,boolean isDebug) {
public static ConflictEventMain init(StreamExecutionEnvironment env, String path, boolean isDebug) {
return new ConflictEventMain(env, path, isDebug);
}
public void run(DataStream<FrameModel> streamSource) {
public void run(DataStream<CrossFrameModel> streamSource) {
SingleOutputStreamOperator<CrossFrameModel> joinLaneStream = streamSource
.connect(env.addSource(new LaneInfoSource()).broadcast())
.flatMap(new ConflictLaneInfoCoFlatMap())
.setParallelism(1)
.name("冲突点-解析数据");
/**
* 转换数据为实体类 并筛选需要计算的数据(路口面 上的数据)
*/
SingleOutputStreamOperator<FrameModel> eventStream = streamSource
SingleOutputStreamOperator<CrossFrameModel> eventStream = joinLaneStream
.flatMap(new ConflictFrameFlatMap())
.setParallelism(1)
.name("冲突点-解析数据");
......@@ -82,7 +87,7 @@ public class ConflictEventMain implements Serializable {
/**
* 按照 crossId + time 分组
*/
SingleOutputStreamOperator<EventCross> processWindowStopAndRuning = streamSource
SingleOutputStreamOperator<EventCross> processWindowStopAndRuning = eventStream
.flatMap(new ConflictCheckConflictFlatMap())
.setParallelism(1)
.name("冲突点-计算是否发生冲突");
......@@ -117,7 +122,7 @@ public class ConflictEventMain implements Serializable {
}
})
.setParallelism(1);
//stringSingleOutputStream.addSink(new EventFileSink(this.path));
stringSingleOutputStream.addSink(new EventFileSink(this.path));
} else {
/**
* 安全专题数据产出
......
package com.wanji.indicators.task.conflictpoint.func;
package com.wanji.indicators.event.cross.conflictpoint.func;
import com.wanji.indicators.model.CarTrackModel;
import com.wanji.indicators.model.ConfigModel;
import com.wanji.indicators.model.EventCross;
import com.wanji.indicators.model.FrameModel;
import com.wanji.indicators.constant.Constant;
import com.wanji.indicators.constant.TurnEnum;
import com.wanji.indicators.model.*;
import com.wanji.indicators.model.event.confilct.EventCross;
import com.wanji.indicators.util.PtInPolyUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.flink.api.common.functions.FlatMapFunction;
import org.apache.flink.util.Collector;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.*;
import java.util.stream.Collectors;
public class ConflictCheckConflictFlatMap implements FlatMapFunction<FrameModel, EventCross> {
public class ConflictCheckConflictFlatMap implements FlatMapFunction<CrossFrameModel, EventCross> {
@Override
public void flatMap(FrameModel frameModel, Collector<EventCross> collector) throws Exception {
public void flatMap(CrossFrameModel frameModel, Collector<EventCross> collector) throws Exception {
ConfigModel configModel = new ConfigModel();
//判断该车道内的是否同时存在行驶车辆和停驶车辆 如果同时存在则 set.size = 2 否则 set.size = 1
Set<Integer> keyStop = new HashSet<>();
......@@ -26,11 +24,11 @@ public class ConflictCheckConflictFlatMap implements FlatMapFunction<FrameModel,
//存放运行的车辆
List<EventCross> listRun = new ArrayList<>();
List<CarTrackModel> trackList = frameModel.getE1FrameParticipant();
List<CarTrackModel> trackList = frameModel.getTrackList();
for (CarTrackModel carTrack : trackList) {
double speed = carTrack.getSpeed();
int trackID = carTrack.getId();
EventCross eventCross = toEventCross(carTrack);
EventCross eventCross = toEventCross(carTrack,frameModel.getGlobalTimeStamp());
if (speed <= 0.0) {
if (keyStop.add(trackID)) {
listStop.add(eventCross);
......@@ -45,6 +43,7 @@ public class ConflictCheckConflictFlatMap implements FlatMapFunction<FrameModel,
for (EventCross a : listStop) {
int trackIDA = a.getTrackID();
String ridA = a.getRid();
//停止车辆的运行角度
double driveAngleA = a.getDriveAngle();
double lngA = a.getLng();
double latA = a.getLat();
......@@ -52,8 +51,8 @@ public class ConflictCheckConflictFlatMap implements FlatMapFunction<FrameModel,
for (CarTrackModel carTrack : trackList) {
if (a.getTrackID() != carTrack.getId() &&
a.getLaneFunction().contains("Constant.STRAIGHT_LINE_CODE") &&
a.getLaneFunction().contains("Constant.LEFT_TURN_CODE") &&
a.getLaneFunction().contains(Constant.STRAIGHT_LINE_CODE) &&
a.getLaneFunction().contains(Constant.LEFT_TURN_CODE) &&
StringUtils.isNotBlank(a.getRid()) &&
a.getRid().equals(carTrack.getRoadnet().getRid())) {
//判定停止车辆前是否有同行车辆
......@@ -69,6 +68,7 @@ public class ConflictCheckConflictFlatMap implements FlatMapFunction<FrameModel,
}
}
}
//从直左混合车道驶出的停车车辆
if (isContinue) {
continue;
}
......@@ -77,14 +77,14 @@ public class ConflictCheckConflictFlatMap implements FlatMapFunction<FrameModel,
String ridB = b.getRid();
boolean isRun = true;
//两方向车道功能都是直行的且行车方向相反则排除
if ("Constant.STRAIGHT_LINE_CODE".equals(a.getLaneFunction()) && "Constant.STRAIGHT_LINE_CODE".equals(b.getLaneFunction())) {
if (Constant.STRAIGHT_LINE_CODE.equals(a.getLaneFunction()) && Constant.STRAIGHT_LINE_CODE.equals(b.getLaneFunction())) {
double angleX = Math.abs(a.getDriveAngle() - b.getDriveAngle());
if (angleX > 160.0 && angleX < 200.0) {
isRun = false;
}
}
//两方向车道功能都是左转的且行车方向相反则排除
if ("Constant.LEFT_TURN_CODE".equals(a.getLaneFunction()) && "Constant.LEFT_TURN_CODE".equals(b.getLaneFunction())) {
if (Constant.LEFT_TURN_CODE.equals(a.getLaneFunction()) && Constant.LEFT_TURN_CODE.equals(b.getLaneFunction())) {
double angleX = Math.abs(a.getDriveAngle() - b.getDriveAngle());
if (angleX > 160.0 && angleX < 200.0) {
isRun = false;
......@@ -99,6 +99,7 @@ public class ConflictCheckConflictFlatMap implements FlatMapFunction<FrameModel,
double distance = PtInPolyUtil.getDistance(head[0], head[1], lngB, latB);//车头位置与行驶车辆的距离
double driveAngleB = b.getDriveAngle();
double angleX = Math.abs(driveAngleA - driveAngleB);
//默认条件:两车距离小于5米,两车视野角度在(60,120)范围内
if (distance < configModel.getConflictTwoCarMaxDist()
&& angleX > configModel.getConflictTwoCarMinAngle()
&& angleX < configModel.getConflictTwoCarMaxAngle()) {//停车车辆与行驶车辆两车角度差计算范围
......@@ -121,8 +122,10 @@ public class ConflictCheckConflictFlatMap implements FlatMapFunction<FrameModel,
if (isIntersectA != 1 && isIntersectB != 1) {
double angle = PtInPolyUtil.getAngle(head[0], head[1], lngB, latB);
double abs = Math.abs(angle - driveAngleA);
if (abs < configModel.getConflictResultAngleDif()) {//停止车辆车头位置与行驶车辆角度差
a.setTrackIdNear(a.getTrackID() + "Constant.COMMA" + b.getTrackID());
if (abs < configModel.getConflictResultAngleDif()) {
//停止车辆车头位置与行驶车辆角度差
a.setTrackIdNear(a.getTrackID() + Constant.COMMA + b.getTrackID());
a.setNearTrackObj(b);
collector.collect(a);
}
}
......@@ -155,12 +158,22 @@ public class ConflictCheckConflictFlatMap implements FlatMapFunction<FrameModel,
}
}
private static EventCross toEventCross(CarTrackModel carTrack){
private static EventCross toEventCross(CarTrackModel carTrack,long timeTamp){
EventCross e = new EventCross();
e.setPlateColor(carTrack.getLicenseColor());
e.setVehicleColor(carTrack.getOriginalColor());
e.setRoadnet(carTrack.getRoadnet());
e.setCrossId(carTrack.getRoadnet().getCrossId());
e.setRid(carTrack.getRoadnet().getRid());
e.setEntryLane(carTrack.getRoadnet().getLaneId());
try {
String[] turns = TurnEnum.getLaneTurn(carTrack.getRoadnet().getTurn());
List<String> turnList = Arrays.asList(turns);
String laneFunction = turnList.stream().filter(o -> Objects.nonNull(o)).collect(Collectors.joining(","));
e.setLaneFunction(laneFunction);
} catch (Exception e1) {
e1.printStackTrace();
}
e.setTrackID(carTrack.getId());
e.setLng(carTrack.getLongitude());
e.setLat(carTrack.getLatitude());
......@@ -169,12 +182,8 @@ public class ConflictCheckConflictFlatMap implements FlatMapFunction<FrameModel,
e.setDriveAngle(carTrack.getCourseAngle());
e.setPlateNumber(carTrack.getPicLicense());
e.setVehicleType(carTrack.getOriginalType());
e.setTime(carTrack.getGlobalTimeStamp());
e.setTime(timeTamp);
e.setAreaDist(carTrack.getWaitingTurnLaneDist());
e.setTravelTime((long) carTrack.getTravelTime());
return e;
......
package com.wanji.indicators.task.conflictpoint.func;
package com.wanji.indicators.event.cross.conflictpoint.func;
import com.wanji.indicators.model.CarTrackModel;
import com.wanji.indicators.model.ConfigModel;
import com.wanji.indicators.model.FrameModel;
import org.apache.commons.lang3.StringUtils;
import org.apache.flink.api.common.functions.FlatMapFunction;
import org.apache.flink.util.Collector;
......@@ -12,7 +11,7 @@ import java.util.*;
public class ConflictCongestionFilterFlatMap implements FlatMapFunction<FrameModel, FrameModel> {
@Override
public void flatMap(FrameModel frameModel, Collector<FrameModel> collector) throws Exception {
List<CarTrackModel> trackList = frameModel.getE1FrameParticipant();
List<CarTrackModel> trackList = frameModel.getTrackList();
ConfigModel configModel = new ConfigModel();
Map<String, List<CarTrackModel>> listMap = new HashMap<>();
......@@ -59,7 +58,7 @@ public class ConflictCongestionFilterFlatMap implements FlatMapFunction<FrameMod
resultList.add(carTrack);
}
}
frameModel.setE1FrameParticipant(resultList);
frameModel.setTrackList(resultList);
collector.collect(frameModel);
}
}
package com.wanji.indicators.task.conflictpoint.func;
package com.wanji.indicators.event.cross.conflictpoint.func;
import com.wanji.indicators.model.EventCross;
import com.wanji.indicators.model.event.confilct.EventCross;
import org.apache.flink.api.common.state.MapState;
import org.apache.flink.api.common.state.MapStateDescriptor;
import org.apache.flink.api.java.tuple.Tuple;
......
package com.wanji.indicators.task.conflictpoint.func;
package com.wanji.indicators.event.cross.conflictpoint.func;
import com.alibaba.fastjson.JSONObject;
import com.wanji.indicators.constant.EventType;
import com.wanji.indicators.model.ConflictPointModelBase;
import com.wanji.indicators.model.EventCross;
import com.wanji.indicators.model.event.confilct.EventCross;
import com.wanji.indicators.util.PtInPolyUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.flink.api.common.functions.FlatMapFunction;
......@@ -14,12 +15,13 @@ public class ConflictEncapsulationResultFlatMap implements FlatMapFunction<Event
private static final Logger log = LoggerFactory.getLogger(ConflictEncapsulationResultFlatMap.class);
@Override
public void flatMap(EventCross event, Collector<String> out) throws Exception {
// log.info("冲突点日志: " + event.getTime() + " " + event.getPlateNumber() + " " +
// event.getAreaDist() + " " +
// event.getCrossing() + " " +
// event.getSpeed() + " ");
if(StringUtils.isNotBlank(event.getPlateNumber())){
log.info("冲突点日志: " + event.getTime() + " " + event.getPlateNumber() + " " +
event.getAreaDist() + " " +
event.getCrossing() + " " +
event.getSpeed() + " ");
// if(StringUtils.isNotBlank(event.getPlateNumber())){
ConflictPointModelBase model = new ConflictPointModelBase();
model.setCrossId(event.getCrossId());
model.setTrackId(event.getTrackID());
model.setPlateNumber(event.getPlateNumber());
......@@ -28,10 +30,12 @@ public class ConflictEncapsulationResultFlatMap implements FlatMapFunction<Event
model.setVehicleColor(event.getVehicleColor());
model.setVehicleBrand(event.getVehicleBrand());
model.setVehicleType(event.getVehicleType() + "");
model.setTrackIdNear(event.getTrackIdNear());
// model.setEventClass(EventType.EVENT.getName());
// model.setEventType(EventType.CONFLICT_POINT.getName());
// model.setTypeCode(EventType.CONFLICT_POINT.getCode());
model.setEventClass(EventType.EVENT.getName());
model.setEventType(EventType.CONFLICT_POINT.getName());
model.setTypeCode(EventType.CONFLICT_POINT.getCode());
model.setDesc("路口面冲突点: 车辆 " + event.getPlateNumber() + "行驶方向为 " + PtInPolyUtil.getDir(event.getDriveAngle()));
model.setDescEn("Intersection conflict point: the driving direction of vehicle "+ "行驶方向为 " + PtInPolyUtil.getDirEn(event.getDriveAngle()));
model.setSpeed(event.getSpeed());
......@@ -66,9 +70,10 @@ public class ConflictEncapsulationResultFlatMap implements FlatMapFunction<Event
model.getEndTime() > model.getStartTime()) {
out.collect(JSONObject.toJSONString(model));
}
model.setNearTackObj(event.getNearTrackObj());
model = null;
}
// }
}
......
package com.wanji.indicators.task.conflictpoint.func;
package com.wanji.indicators.event.cross.conflictpoint.func;
import com.wanji.indicators.constant.Constant;
import com.wanji.indicators.model.CarTrackModel;
import com.wanji.indicators.model.ConfigModel;
import com.wanji.indicators.model.CrossFrameModel;
import com.wanji.indicators.model.FrameModel;
import com.wanji.indicators.util.CommonUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.flink.api.common.functions.FlatMapFunction;
import org.apache.flink.util.Collector;
......@@ -12,27 +15,25 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class ConflictFrameFlatMap implements FlatMapFunction<FrameModel, FrameModel> {
static Map<Integer, CarTrackModel.RoadNet> carRoadnetMap = new HashMap<>();
public class ConflictFrameFlatMap implements FlatMapFunction<CrossFrameModel, CrossFrameModel> {
@Override
public void flatMap(FrameModel frameModel, Collector<FrameModel> collector) throws Exception {
List<CarTrackModel> trackList = frameModel.getE1FrameParticipant();
public void flatMap(CrossFrameModel frameModel, Collector<CrossFrameModel> collector) throws Exception {
List<CarTrackModel> trackList = frameModel.getTrackList();
ConfigModel configModel = new ConfigModel();
if (configModel.getConflictIsOpen() == 1) {
List<CarTrackModel> resultList = new ArrayList<>();
for (CarTrackModel carTrack : trackList) {
CarTrackModel.RoadNet roadNet = carTrack.getRoadnet();
//路口内
if (StringUtils.equals(carTrack.getRoadnet().getLaneId(), "null")) {
//路口内无车道ID、路段ID信息,从上一次运行缓存获取标记为从哪个车道出来
//筛选在路口内的车辆
if (roadNet.getInCrossFlag()== Constant.CROSSING) {
resultList.add(carTrack);
} else {
carRoadnetMap.put(carTrack.getId(),roadNet);
}
}
frameModel.setE1FrameParticipant(resultList);
frameModel.setTrackList(resultList);
collector.collect(frameModel);
}
}
......
package com.wanji.indicators.event.cross.conflictpoint.func;
import com.wanji.indicators.entity.BaseLaneInfo;
import com.wanji.indicators.model.CarTrackModel;
import com.wanji.indicators.model.CrossFrameModel;
import com.wanji.indicators.model.FrameModel;
import org.apache.commons.lang3.StringUtils;
import org.apache.flink.streaming.api.functions.co.CoFlatMapFunction;
import org.apache.flink.util.Collector;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class ConflictLaneInfoCoFlatMap implements CoFlatMapFunction<CrossFrameModel, Map<String, BaseLaneInfo>, CrossFrameModel> {
private Map<String, BaseLaneInfo> map = new HashMap();
@Override
public void flatMap1(CrossFrameModel frameModel, Collector<CrossFrameModel> collector) throws Exception {
List<CarTrackModel> trackList = frameModel.getTrackList();
List<CarTrackModel> resList = new ArrayList<>();
for (CarTrackModel carTrack : trackList) {
String entryLane = carTrack.getRoadnet().getLaneId();
BaseLaneInfo baseLaneInfo = map.get(entryLane);
if (baseLaneInfo != null) {
carTrack.getRoadnet().setTurn(baseLaneInfo.getTurn());
} else {
continue;
}
resList.add(carTrack);
}
frameModel.setTrackList(resList);
collector.collect(frameModel);
}
@Override
public void flatMap2(Map<String, BaseLaneInfo> hashMap, Collector<CrossFrameModel> collector) throws Exception {
this.map = hashMap;
}
}
package com.wanji.indicators.task.conflictpoint.func;
package com.wanji.indicators.event.cross.conflictpoint.func;
import com.wanji.indicators.model.CarTrackModel;
import com.wanji.indicators.model.FrameModel;
......@@ -17,7 +17,7 @@ public class ConflictWaitingAreaCoFlatMap implements CoFlatMapFunction<FrameMode
@Override
public void flatMap1(FrameModel frameModel, Collector<FrameModel> collector) throws Exception {
List<CarTrackModel> resultList = new ArrayList<>();
List<CarTrackModel> trackList = frameModel.getE1FrameParticipant();
List<CarTrackModel> trackList = frameModel.getTrackList();
for(CarTrackModel carTrack : trackList){
String entryLane = carTrack.getRoadnet().getLaneId();
if (StringUtils.isNotBlank(entryLane)) {
......@@ -31,7 +31,7 @@ public class ConflictWaitingAreaCoFlatMap implements CoFlatMapFunction<FrameMode
}
}
}
frameModel.setE1FrameParticipant(resultList);
frameModel.setTrackList(resultList);
collector.collect(frameModel);
}
......
//package com.wanji.indicators.task.conflictpoint.ttc;
package com.wanji.indicators.event.cross.conflictpoint.ttc;//package com.wanji.indicators.task.conflictpoint.ttc;
//
//import com.alibaba.fastjson.JSONObject;
//import com.mapabc.constant.Constant;
......
//package com.wanji.indicators.task.conflictpoint.ttc;
package com.wanji.indicators.event.cross.conflictpoint.ttc;//package com.wanji.indicators.task.conflictpoint.ttc;
//
//import com.mapabc.model.event.EventCross;
//
......
package com.wanji.indicators.event.cross.congestion;
import com.wanji.indicators.event.cross.congestion.funcnew.*;
import com.wanji.indicators.model.BaseEventResultModel;
import com.wanji.indicators.model.FrameModel;
import com.wanji.indicators.model.event.congestion.CongestionFrameModel;
import com.wanji.indicators.model.event.congestion.CongestionModel;
import com.wanji.indicators.model.event.congestion.CongestionOverflowModel;
import com.wanji.indicators.source.ConsulAreaSource;
import com.wanji.indicators.source.CrossShapeSource;
import com.wanji.indicators.source.RidDirSource;
import com.wanji.indicators.source.WaitLaneSource;
import com.wanji.indicators.util.PropertiesHelper;
import org.apache.flink.api.common.functions.FlatMapFunction;
import org.apache.flink.api.common.serialization.SimpleStringSchema;
import org.apache.flink.streaming.api.datastream.DataStream;
import org.apache.flink.streaming.api.datastream.SingleOutputStreamOperator;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.connectors.kafka.FlinkKafkaProducer;
import org.apache.flink.streaming.connectors.kafka.internals.KeyedSerializationSchemaWrapper;
import org.apache.flink.util.Collector;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.Serializable;
import java.util.Properties;
/**
* 拥堵溢出检测
* @author fengyi
*/
public class CongestionEventMainNew implements Serializable {
private static final Logger log = LoggerFactory.getLogger(CongestionEventMainNew.class);
private StreamExecutionEnvironment env;
private PropertiesHelper instance;
private Properties p;
private String path;
//本地调试设为true输出结果保存到文件
private boolean isDebug = false;
private CongestionEventMainNew(StreamExecutionEnvironment env, String path, boolean isDebug) {
this.env = env;
this.instance = PropertiesHelper.getInstance();
this.p = instance.getProperties();
this.path = path;
this.isDebug = isDebug;
}
public static CongestionEventMainNew init(StreamExecutionEnvironment env, String path, boolean isDebug) {
return new CongestionEventMainNew(env, path,isDebug);
}
private CongestionEventMainNew(StreamExecutionEnvironment env) {
this.env = env;
this.instance = PropertiesHelper.getInstance();
this.p = instance.getProperties();
}
public static CongestionEventMainNew init(StreamExecutionEnvironment env) {
return new CongestionEventMainNew(env);
}
public void run(DataStream<FrameModel> thinningDataStream) {
FlinkKafkaProducer<String> kafkaProducer = new FlinkKafkaProducer<>(
p.getProperty("cross.event.data.topic"),
new KeyedSerializationSchemaWrapper<>(new SimpleStringSchema()),
instance.getProducerProperties(), FlinkKafkaProducer.Semantic.NONE);
//解析数据
SingleOutputStreamOperator<CongestionFrameModel> accidentFrameModelFilter = null;
// thinningDataStream
// .flatMap(new CongestionFlatMap())
// .setParallelism(1)
// .name("路口溢出-解析数据");
//计算车辆在路口内的旅行时间
SingleOutputStreamOperator<CongestionFrameModel> checkDataKeyedProcess = accidentFrameModelFilter
.keyBy(CongestionFrameModel::getCrossId)
.process(new CongestionCheckDataKeyedProcess())
.setParallelism(1)
.name("路口溢出-计算车辆在路口内的旅行时间");
//匹配待转区
SingleOutputStreamOperator<CongestionFrameModel> checkWaitLaneKeyedProcess = checkDataKeyedProcess
.connect(env.addSource(new WaitLaneSource()).broadcast())
.flatMap(new CongestionCheckWaitLaneCoFlatMap())
.setParallelism(1)
.name("路口溢出-匹配待转区");
//匹配拥堵检测区域
SingleOutputStreamOperator<CongestionFrameModel> checkCongestionArea = checkWaitLaneKeyedProcess
.connect(env.addSource(new ConsulAreaSource()).broadcast())
.flatMap(new CongestionAreaCheckCoFlatMap())
.setParallelism(1)
.name("事故检测-匹配拥堵检测区域");
//匹配对应拥堵出口rid的方向
SingleOutputStreamOperator<CongestionFrameModel> checkDirCoFlatMap = checkCongestionArea
.connect(env.addSource(new RidDirSource()).broadcast())
.flatMap(new CongestionCheckDirCoFlatMap())
.setParallelism(1)
.name("路口溢出-匹配车辆对应的出口rid的方向");
//计算是否疑似路口溢出 开始/消散
SingleOutputStreamOperator<CongestionModel> checkCongestionKeyedProcess = checkDirCoFlatMap
.keyBy(CongestionFrameModel::getCrossId)
.process(new CongestionKeyedProcess())
.setParallelism(1)
.name("路口溢出-计算是否路口溢出");
//读取路口形状并根据 "车道转向功能" 和 "进口rid" 匹配对应的 "出口rid"
// SingleOutputStreamOperator<CongestionModel> checkRidInCoFlatMap = checkCongestionKeyedProcess
// .connect(env.addSource(new CrossShapeSource()).broadcast())
// //.flatMap(new CongestionCheckOutRidCoFlatMap())
// //.setParallelism(1)
// .name("路口溢出-匹配车辆对应的出口rid");
//路口溢出-逻辑去重
SingleOutputStreamOperator<CongestionOverflowModel> congestionOverflowStream = checkCongestionKeyedProcess
.keyBy("crossId", "ridOut", "startTime")
.process(new CongestionValueStateKeyedProcess())
.setParallelism(1)
.name("路口溢出-逻辑去重");
if (!isDebug) {
SingleOutputStreamOperator<String> stringSingleOutputStreamOperator = congestionOverflowStream
.flatMap(new CongestionToStringFlatMap())
.setParallelism(1)
.name("路口溢出-封装结果集");
stringSingleOutputStreamOperator.addSink(kafkaProducer).setParallelism(1).name("路口溢出-结果输出至kafka");
stringSingleOutputStreamOperator.print("拥堵溢出检测-结果").name("路口溢出-结果打印");
} else {
SingleOutputStreamOperator<BaseEventResultModel> baseEventResultModelStream = congestionOverflowStream.flatMap(new FlatMapFunction<CongestionOverflowModel, BaseEventResultModel>() {
@Override
public void flatMap(CongestionOverflowModel congestionOverflowModel, Collector<BaseEventResultModel> collector) throws Exception {
collector.collect(congestionOverflowModel);
}
});
// baseEventResultModelStream.addSink(new EventFileSink(this.path));
}
}
}
package com.wanji.indicators.event.cross.congestion.funcnew;
import com.wanji.indicators.constant.Constant;
import com.wanji.indicators.model.ConfigModel;
import com.wanji.indicators.model.event.congestion.CongestionAreaDo;
import com.wanji.indicators.model.event.congestion.CongestionFrameModel;
import com.wanji.indicators.util.PtInPolyUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.flink.streaming.api.functions.co.CoFlatMapFunction;
import org.apache.flink.util.Collector;
import java.util.*;
/**
* 2022/3/17 15:52
*
* @auther fengyi
*/
public class CongestionAreaCheckCoFlatMap implements CoFlatMapFunction<CongestionFrameModel, HashMap<String, Map<String, CongestionAreaDo>>, CongestionFrameModel> {
private HashMap<String, Map<String, CongestionAreaDo>> hashMap = new HashMap();
@Override
public void flatMap1(CongestionFrameModel congestionFrameModel, Collector<CongestionFrameModel> collector) throws Exception {
List<CongestionFrameModel.CarTrack> trackList = congestionFrameModel.getTrackList();
ConfigModel configModel = congestionFrameModel.getConfigModel();
List<CongestionFrameModel.CarTrack> list = new ArrayList<>();
Set<Integer> set = new HashSet<>();
Map<String, CongestionAreaDo> congestionAreaDoMap = hashMap.get(congestionFrameModel.getCrossId());
if (congestionAreaDoMap != null) {
Map<String, Integer> map = new HashMap<>();
for (CongestionAreaDo congestionAreaDo : congestionAreaDoMap.values()) {
int laneNum = congestionAreaDo.getLaneNum();
if (laneNum > 0) {
//存入各出口rid对应的车道数
map.put(congestionAreaDo.getRid(), laneNum);
}
}
congestionFrameModel.setCongestionInfo(map);
for (CongestionFrameModel.CarTrack carTrack : trackList) {
String entryLane = carTrack.getEntryLane();
if (carTrack.getCrossing() == Constant.CROSSING && carTrack.getSpeed() < configModel.getAbnormalParkCongestSpeed() && StringUtils.isNotBlank(entryLane)) {
for (CongestionAreaDo congestionAreaDo : congestionAreaDoMap.values()) {
String ridIn = entryLane.substring(0, 23);
//判断是否属于该方向验证的入口rid数据
if (congestionAreaDo.getRidInArr().contains(ridIn)) {
PtInPolyUtil.Point point = new PtInPolyUtil.Point(carTrack.getLng(), carTrack.getLat());
boolean isIn = PtInPolyUtil.isPtInPoly(point, congestionAreaDo.getPoints());
if (isIn) {
if (set.add(carTrack.getTrackID())) {
carTrack.setRidOut(congestionAreaDo.getRid());
list.add(carTrack);
}
}
}
}
}
}
for (CongestionFrameModel.CarTrack carTrack : trackList) {
if (!set.contains(carTrack.getTrackID())) {
list.add(carTrack);
}
}
congestionFrameModel.setTrackList(list);
}
collector.collect(congestionFrameModel);
}
@Override
public void flatMap2(HashMap<String, Map<String, CongestionAreaDo>> stringCongestionAreaDoHashMap, Collector<CongestionFrameModel> collector) throws Exception {
this.hashMap = stringCongestionAreaDoHashMap;
}
}
package com.wanji.indicators.event.cross.congestion.funcnew;
import com.wanji.indicators.model.event.congestion.CongestionFrameModel;
import org.apache.flink.api.common.state.MapState;
import org.apache.flink.api.common.state.MapStateDescriptor;
import org.apache.flink.configuration.Configuration;
import org.apache.flink.streaming.api.functions.KeyedProcessFunction;
import org.apache.flink.util.Collector;
import java.util.*;
/**
* 2021/11/18 16:47
*
* @auther fengyi
*/
public class CongestionCheckDataKeyedProcess extends KeyedProcessFunction<String, CongestionFrameModel, CongestionFrameModel> {
private MapState<Integer, CongestionFrameModel.CarTrack> mapState;
@Override
public void open(Configuration parameters) throws Exception {
mapState = getRuntimeContext().getMapState(new MapStateDescriptor<>("mapStateCongestion_ridCheck_11x", Integer.class, CongestionFrameModel.CarTrack.class));
}
@Override
public void processElement(CongestionFrameModel congestionFrameModel, Context context, Collector<CongestionFrameModel> collector) throws Exception {
long timeNow = congestionFrameModel.getTime();
Map<Integer,CongestionFrameModel.CarTrack> map = new HashMap<>();
List<CongestionFrameModel.CarTrack> trackList = congestionFrameModel.getTrackList();
List<CongestionFrameModel.CarTrack> list = new ArrayList<>();
for (CongestionFrameModel.CarTrack carTrack : trackList) {
int trackID = carTrack.getTrackID();
map.put(trackID, carTrack);
CongestionFrameModel.CarTrack carTrackFirst = mapState.get(trackID);
if (carTrackFirst == null) {
carTrack.setTravelTime(0);
mapState.put(trackID, carTrack);
} else {
long duration = carTrack.getTime() - carTrackFirst.getTime();
if (duration > 0L) {
carTrack.setTravelTime(duration/1000.0);
}
}
list.add(carTrack);
}
//清除过期数据
Iterator<CongestionFrameModel.CarTrack> iterator = mapState.values().iterator();
List<CongestionFrameModel.CarTrack> listMapState = new ArrayList<>();
while (iterator.hasNext()) {
CongestionFrameModel.CarTrack next = iterator.next();
listMapState.add(next);
}
for (CongestionFrameModel.CarTrack next : listMapState) {
int trackID = next.getTrackID();
CongestionFrameModel.CarTrack carTrack = map.get(trackID);
//查询当前帧数据中没有此trackID 说明该目标 上一帧有 当前帧没有
if (carTrack == null) {
//计算当前此目标与时间差多少毫秒 若超过10秒则清除该目标
long timeX = timeNow - next.getTime();
if (timeX > 10000L) {
mapState.remove(trackID);
// System.out.println(" 数据过期 " + trackID + " " + timeX + " " + list.size());
}
}
}
//发送数据
if (!list.isEmpty()) {
congestionFrameModel.setTrackList(list);
collector.collect(congestionFrameModel);
}
}
}
package com.wanji.indicators.event.cross.congestion.funcnew;
import com.wanji.indicators.constant.Constant;
import com.wanji.indicators.model.event.congestion.CongestionFrameModel;
import org.apache.commons.lang3.StringUtils;
import org.apache.flink.streaming.api.functions.co.CoFlatMapFunction;
import org.apache.flink.util.Collector;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
/**
* 2022/1/12 1:01
*
* @auther fengyi
*/
public class CongestionCheckDirCoFlatMap implements CoFlatMapFunction<CongestionFrameModel, HashMap<String, String>, CongestionFrameModel> {
private HashMap<String, String> ridDirMap = new HashMap<>();
@Override
public void flatMap1(CongestionFrameModel congestionFrameModel, Collector<CongestionFrameModel> collector) throws Exception {
List<CongestionFrameModel.CarTrack> trackList = congestionFrameModel.getTrackList();
List<CongestionFrameModel.CarTrack> list = new ArrayList<>();
for (CongestionFrameModel.CarTrack carTrack : trackList) {
String ridOut = carTrack.getRidOut();
if (StringUtils.isNotBlank(ridOut)) {
String dirCode = ridDirMap.get(ridOut + Constant.MARK);
if (StringUtils.isNotBlank(dirCode)){
carTrack.setRidOutDir(dirCode);
} else {
carTrack.setRidOutDir("");
}
}
list.add(carTrack);
}
congestionFrameModel.setTrackList(list);
collector.collect(congestionFrameModel);
}
@Override
public void flatMap2(HashMap<String, String> stringStringHashMap, Collector<CongestionFrameModel> collector) throws Exception {
this.ridDirMap = stringStringHashMap;
}
}
package com.wanji.indicators.event.cross.congestion.funcnew;
import com.wanji.indicators.constant.Constant;
import com.wanji.indicators.model.event.congestion.CongestionModel;
import com.wanji.indicators.model.event.congestion.CrossShapeModel;
import org.apache.flink.streaming.api.functions.co.CoFlatMapFunction;
import org.apache.flink.util.Collector;
import java.util.HashMap;
/**
* 2022/1/11 18:13
*
* @auther fengyi
*/
public class CongestionCheckOutRidCoFlatMap implements CoFlatMapFunction<CongestionModel, HashMap<String, CrossShapeModel>, CongestionModel> {
private HashMap<String, CrossShapeModel> hashMap = new HashMap<>();
@Override
public void flatMap1(CongestionModel congestionFrameModel, Collector<CongestionModel> collector) throws Exception {
String ridOut = congestionFrameModel.getRidOut();
String key = ridOut + Constant.MARK + Constant.STRAIGHT_LINE_CODE;
CrossShapeModel crossShapeModel = hashMap.get(key);
if (crossShapeModel != null) {
congestionFrameModel.setRidIn(crossShapeModel.getRidIn());
}
collector.collect(congestionFrameModel);
}
@Override
public void flatMap2(HashMap<String, CrossShapeModel> stringCrossShapeModelHashMap, Collector<CongestionModel> collector) throws Exception {
this.hashMap = stringCrossShapeModelHashMap;
}
}
package com.wanji.indicators.event.cross.congestion.funcnew;
import com.wanji.indicators.model.event.congestion.CongestionFrameModel;
import org.apache.commons.lang3.StringUtils;
import org.apache.flink.streaming.api.functions.co.CoFlatMapFunction;
import org.apache.flink.util.Collector;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
/**
* 2021/11/19 17:31
*
* @auther fengyi
*/
public class CongestionCheckWaitLaneCoFlatMap implements CoFlatMapFunction<CongestionFrameModel, HashMap<String, Integer>, CongestionFrameModel> {
private HashMap<String, Integer> mapWaitLane = new HashMap<>();
@Override
public void flatMap1(CongestionFrameModel accidentCongestionFrameModel, Collector<CongestionFrameModel> collector) throws Exception {
List<CongestionFrameModel.CarTrack> trackList = accidentCongestionFrameModel.getTrackList();
List<CongestionFrameModel.CarTrack> list = new ArrayList<>();
for(CongestionFrameModel.CarTrack carTrack : trackList) {
String entryLane = carTrack.getEntryLane();
if (StringUtils.isNotBlank(entryLane)) {
//待转区距离停止线的距离
Integer waitLaneDistance = mapWaitLane.get(entryLane);
if( waitLaneDistance != null ) {
if (carTrack.getAreaDist() > waitLaneDistance + 2.5) {
carTrack.setWaitLaneDistance(waitLaneDistance);
list.add(carTrack);
}
} else {
list.add(carTrack);
}
}
}
accidentCongestionFrameModel.setTrackList(list);
collector.collect(accidentCongestionFrameModel);
}
@Override
public void flatMap2(HashMap<String, Integer> stringIntegerHashMap, Collector<CongestionFrameModel> collector) throws Exception {
this.mapWaitLane = stringIntegerHashMap;
}
}
package com.wanji.indicators.event.cross.congestion.funcnew;
import com.wanji.indicators.constant.Constant;
import com.wanji.indicators.model.ConfigModel;
import com.wanji.indicators.model.CrossFrameModel;
import com.wanji.indicators.model.FrameModel;
import org.apache.flink.streaming.api.functions.co.CoFlatMapFunction;
import org.apache.flink.util.Collector;
import java.util.HashMap;
/**
* 2022/2/16 16:42
*
* @auther fengyi
*/
public class CongestionConfigCoFlatMap implements CoFlatMapFunction<CrossFrameModel, HashMap<String, ConfigModel>, CrossFrameModel> {
private HashMap<String, ConfigModel> hashMap;
@Override
public void flatMap1(CrossFrameModel frameModel, Collector<CrossFrameModel> collector) throws Exception {
if (hashMap != null) {
ConfigModel model = hashMap.get(frameModel.getCrossId());
if (model != null) {
if (model.getOverFlowCongestIsOpen() == Constant.OPEN) {
frameModel.setConfigModel(model);
collector.collect(frameModel);
}
} else {
frameModel.setConfigModel(new ConfigModel());
collector.collect(frameModel);
}
}
}
@Override
public void flatMap2(HashMap<String, ConfigModel> stringConfigModelHashMap, Collector<CrossFrameModel> collector) throws Exception {
this.hashMap = stringConfigModelHashMap;
}
}
package com.wanji.indicators.event.cross.congestion.funcnew;
import com.wanji.indicators.constant.Constant;
import com.wanji.indicators.model.CarTrackModel;
import com.wanji.indicators.model.ConfigModel;
import com.wanji.indicators.model.CrossFrameModel;
import com.wanji.indicators.model.FrameModel;
import com.wanji.indicators.model.event.congestion.CongestionFrameModel;
import org.apache.commons.lang3.StringUtils;
import org.apache.flink.api.common.functions.FlatMapFunction;
import org.apache.flink.util.Collector;
import org.springframework.beans.BeanUtils;
import java.util.ArrayList;
import java.util.List;
/**
* 2021/11/18 16:44
*
* @auther fengyi
*/
public class CongestionFlatMap implements FlatMapFunction<CrossFrameModel, CongestionFrameModel> {
@Override
public void flatMap(CrossFrameModel frameModel, Collector<CongestionFrameModel> collector) throws Exception {
List<CarTrackModel> trackList = frameModel.getTrackList();
ConfigModel configModel = frameModel.getConfigModel();
if (configModel.getOverFlowCongestIsOpen() == Constant.OPEN) {
List<CongestionFrameModel.CarTrack> list = new ArrayList<>();
for (CarTrackModel carTrack : trackList) {
if (StringUtils.equals(carTrack.getRoadnet().getLaneId(), "null")) {
CongestionFrameModel.CarTrack car = new CongestionFrameModel.CarTrack();
BeanUtils.copyProperties(carTrack,car);
list.add(car);
}
}
CongestionFrameModel model = new CongestionFrameModel();
model.setConfigModel(configModel);
model.setCrossId(frameModel.getCrossId());
model.setTime(frameModel.getGlobalTimeStamp());
model.setTrackList(list);
collector.collect(model);
}
}
}
package com.wanji.indicators.event.cross.congestion.funcnew;
import com.wanji.indicators.constant.Constant;
import com.wanji.indicators.constant.EventType;
import com.wanji.indicators.model.ConfigModel;
import com.wanji.indicators.model.event.congestion.AccidentCongestionModel;
import com.wanji.indicators.model.event.congestion.CongestionFrameModel;
import com.wanji.indicators.model.event.congestion.CongestionModel;
import com.wanji.indicators.util.DateUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.flink.api.common.state.MapState;
import org.apache.flink.api.common.state.MapStateDescriptor;
import org.apache.flink.configuration.Configuration;
import org.apache.flink.streaming.api.functions.KeyedProcessFunction;
import org.apache.flink.util.Collector;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 2021/11/19 17:54
*
* @auther fengyi
*/
public class CongestionKeyedProcess extends KeyedProcessFunction<String, CongestionFrameModel, CongestionModel> {
private static final Logger log = LoggerFactory.getLogger(CongestionKeyedProcess.class);
private MapState<String, AccidentCongestionModel> mapState;
@Override
public void open(Configuration parameters) throws Exception {
mapState = getRuntimeContext().getMapState(new MapStateDescriptor<>("mapStateCongestion_01x33330", String.class, AccidentCongestionModel.class));
}
@Override
public void processElement(CongestionFrameModel congestionFrameModel, Context context, Collector<CongestionModel> collector) throws Exception {
long timeNow = congestionFrameModel.getTime();
ConfigModel configModel = congestionFrameModel.getConfigModel();
Map<String, Integer> congestionInfo = congestionFrameModel.getCongestionInfo();
//按rid分组当前帧的车辆
Map<String, List<CongestionFrameModel.CarTrack>> ridMap = keyByRidMap(congestionFrameModel);
for (String ridKey : ridMap.keySet()) {
List<CongestionFrameModel.CarTrack> list = ridMap.get(ridKey);
AccidentCongestionModel congestionAgo = mapState.get(ridKey);
if (congestionAgo != null) {
//计算时间差
long timeX = timeNow - congestionAgo.getTime();
//获取上一帧累计的拥堵持续时间
long duration = congestionAgo.getDuration();
if (timeX > 0L && timeX < 10000L) {
duration += timeX;
}
//构建缓存数据
AccidentCongestionModel model = getStateModel(ridKey, duration, timeNow, congestionAgo);
//构建结果数据
CongestionModel result = getResult(model, congestionFrameModel, list.get(0).getRid());
//读取拥堵三色预警时间阈值配置,单位秒
long minDuration = 30;//configModel.getMinDuration(EventType.OVERFLOW_CONGESTION.getCode());
//计算当前帧是否拥堵 拥堵状态是否持续
boolean congestion = isCongestion(list, configModel.getOverFlowCongestDissipationCarNums(), configModel);
if (congestion) {
//若当前帧拥堵则将当前帧时间缓存更新至状态 更新了拥堵的持续时间
mapState.put(ridKey, model);
//判定是否输出路口溢出事件
if (model.getDuration() > minDuration) {
collector.collect(result);
log.info("LOG_EVENT_CONGESTION >>> 拥堵持续: " + ridKey +
" " + DateFormatUtils.format(model.getStartTime(), DateUtil.YYYY_MM_DD_HH_MM_SS) +
" - " + DateFormatUtils.format(model.getTime(),DateUtil.YYYY_MM_DD_HH_MM_SS) +
" du: " + model.getDuration() + " ridOut: " + ridKey +
" dir:" + list.get(0).getRidOutDir() + " checkTime: " + minDuration);
}
} else {
//计算是否消散 未消散则持续输出数据
if (dissipation(timeNow, timeX, model.getDuration(), minDuration, ridKey, congestionFrameModel, congestionAgo, model)) {
collector.collect(result);
}
}
} else {
if (congestionInfo != null && congestionInfo.get(ridKey) != null) {
Integer lane_num = congestionInfo.get(ridKey);
//计算当前帧是否拥堵 拥堵则将状态放入缓存
checkCongestion(ridKey, congestionFrameModel, list, lane_num);
}
}
}
}
/**
* 构建缓存数据结构 中间缓存存储的数据
* @param ridKey
* @param duration
* @param nowTime
* @param congestionAgo
* @return
*/
private AccidentCongestionModel getStateModel(String ridKey, long duration, long nowTime, AccidentCongestionModel congestionAgo) {
AccidentCongestionModel model = new AccidentCongestionModel();
model.setKey(ridKey);
model.setStartTime(congestionAgo.getStartTime() / 1000 * 1000);
model.setTime(nowTime);
model.setDuration(duration);
model.setRidOut(congestionAgo.getRidOut());
model.setRidOutDir(congestionAgo.getRidOutDir());
model.setLng(congestionAgo.getLng());
model.setLat(congestionAgo.getLat());
model.setRecoveryCross(congestionAgo.getRecoveryCross());
return model;
}
/**
* 构建结果集
* @param model
* @param congestionFrameModel
* @return
*/
private CongestionModel getResult(AccidentCongestionModel model, CongestionFrameModel congestionFrameModel, String ridIn) {
CongestionModel result = new CongestionModel();
result.setCrossId(congestionFrameModel.getCrossId());
result.setRidIn(ridIn);
result.setStartTime(model.getStartTime());
result.setEndTime(model.getTime());
long duReal = model.getTime() - model.getStartTime();
if (duReal - model.getDuration() > 120000L) {
result.setDuration(duReal);
} else {
result.setDuration(model.getDuration());
}
result.setRidOut(model.getRidOut());
result.setDirection(model.getRidOutDir());
result.setLng(model.getLng());
result.setLat(model.getLat());
if (StringUtils.isNotBlank(result.getDirection()) && !"null".equals(result.getDirection())) {
result.setDirection(result.getDirection() + "出口");
} else {
result.setDirection("");
}
result.setRecoveryCross(model.getRecoveryCross());
result.setConfigModel(congestionFrameModel.getConfigModel());
return result;
}
/**
* 计算消散状态
* @param timeNow
* @param timeX
* @param duration
* @param minDuration
* @param ridKey
* @param congestionFrameModel
* @param congestionAgo
* @param model
* @return
* @throws Exception
*/
private boolean dissipation(long timeNow, long timeX, long duration, long minDuration, String ridKey, CongestionFrameModel congestionFrameModel,
AccidentCongestionModel congestionAgo, AccidentCongestionModel model) throws Exception {
long du = timeNow - congestionAgo.getStartTime();
ConfigModel configModel = congestionFrameModel.getConfigModel();
//若当前计算到不拥堵了 则延迟60s清除拥堵缓存标识
if (timeX > configModel.getOverFlowCongestDissipationDuration() || du > configModel.getOverFlowCongestSplitMaxDuration()) {
mapState.remove(ridKey);
mapState.remove(congestionFrameModel.getCrossId());
log.info("LOG_EVENT_CONGESTION >>> 拥堵消散: " + ridKey + " du:" + duration +
" " + DateFormatUtils.format(model.getStartTime(),DateUtil.YYYY_MM_DD_HH_MM_SS) +
" - " + DateFormatUtils.format(model.getTime(),DateUtil.YYYY_MM_DD_HH_MM_SS) +
" | " + DateFormatUtils.format(timeNow,DateUtil.YYYY_MM_DD_HH_MM_SS) +
" - " + DateFormatUtils.format(congestionAgo.getTime(),DateUtil.YYYY_MM_DD_HH_MM_SS) +
" timeX:" + timeX);
} else {
//若当前帧拥堵则将当前帧时间缓存至状态 更新了拥堵的持续时间
mapState.put(ridKey, model);
//判定是否输出路口溢出事件
if (duration > minDuration) {
return true;
} else {
//若当前帧拥堵持续时间未满足
if (timeX > configModel.getOverFlowCongestUnsatisfiedDurationClear()) {
mapState.remove(ridKey);
mapState.remove(congestionFrameModel.getCrossId());
log.info("LOG_EVENT_CONGESTION >>> 不足30秒-清除缓存-拥堵消散: " + ridKey + " du:" + duration +
" " + DateFormatUtils.format(model.getStartTime(),DateUtil.YYYY_MM_DD_HH_MM_SS) +
" - " + DateFormatUtils.format(model.getTime(),DateUtil.YYYY_MM_DD_HH_MM_SS) +
" | " + DateFormatUtils.format(timeNow,DateUtil.YYYY_MM_DD_HH_MM_SS) +
" - " + DateFormatUtils.format(congestionAgo.getTime(),DateUtil.YYYY_MM_DD_HH_MM_SS) +
" timeX:" + timeX);
}
}
}
return false;
}
/**
* 计算拥堵状态
* @param ridKey
* @param congestionFrameModel
* @param list
* @throws Exception
*/
private void checkCongestion (String ridKey, CongestionFrameModel congestionFrameModel,
List<CongestionFrameModel.CarTrack> list, int congestCarNum) throws Exception {
boolean congestion = isCongestion(list, congestCarNum, congestionFrameModel.getConfigModel());
if (congestion) {
AccidentCongestionModel crossCongestion = mapState.get(congestionFrameModel.getCrossId());
if (crossCongestion == null) {
CongestionFrameModel.CarTrack carTrack = list.get(0);
AccidentCongestionModel model = new AccidentCongestionModel();
model.setKey(ridKey);
model.setStartTime(congestionFrameModel.getTime() / 1000 * 1000);
model.setTime(congestionFrameModel.getTime());
model.setDuration(0L);
model.setRidOut(ridKey);
model.setRidOutDir(carTrack.getRidOutDir());
model.setLng(carTrack.getLng());
model.setLat(carTrack.getLat());
model.setRecoveryCross(carTrack.getRecoveryCross());
//若当前帧拥堵则将当前帧时间缓存至状态
mapState.put(ridKey, model);
mapState.put(congestionFrameModel.getCrossId(), model);
log.info("LOG_EVENT_CONGESTION >>> 发现拥堵: " + ridKey +
" " + DateFormatUtils.format(model.getStartTime(),DateUtil.YYYY_MM_DD_HH_MM_SS) +
" - " + DateFormatUtils.format(model.getTime(),DateUtil.YYYY_MM_DD_HH_MM_SS) +
" ridOut: " + carTrack.getRidOut() + " dir:" + carTrack.getRidOutDir());
}
}
}
/**
* 计算当前帧是否拥堵
* @param list 当前帧车辆集合
* @param checkNum 拥堵车辆判定数量阈值
* @return
*/
private boolean isCongestion(List<CongestionFrameModel.CarTrack> list, long checkNum,ConfigModel configModel) {
long congestionNum = 0;
for (CongestionFrameModel.CarTrack carTrack : list) {
double waitLaneDistance = carTrack.getWaitLaneDistance() + 2.5;
double areaDist = carTrack.getAreaDist();
//计算车辆是否驶出待转区 若驶出待转区则 areaDist 大于 waitLaneDistance
if (areaDist > waitLaneDistance) {
//计算旅行时间超过10s且车速低于10km/h的车辆
if (carTrack.getTravelTime() > configModel.getOverFlowCongestCarTravelTime()
&& carTrack.getSpeed() < configModel.getOverFlowCongestSpeed()) {
congestionNum++;
}
}
}
//行驶缓慢的车辆数超过传值的阈值则认为路口发生路口溢出
if (congestionNum > checkNum) {
return true;
} else {
return false;
}
}
/**
* 按照rid分组计算当前帧的所有车辆
*
* @param accidentCongestionFrameModel
* @return
*/
private Map<String, List<CongestionFrameModel.CarTrack>> keyByRidMap(CongestionFrameModel accidentCongestionFrameModel) {
List<CongestionFrameModel.CarTrack> trackList = accidentCongestionFrameModel.getTrackList();
Map<String, List<CongestionFrameModel.CarTrack>> listMap = new HashMap<>();
for (CongestionFrameModel.CarTrack carTrack : trackList) {
boolean isOk = false;
String ridOut = carTrack.getRidOut();
//出口车道第一个渠化段
if(carTrack.getCrossing() != Constant.CROSSING && carTrack.getStopLineDist() == -1 && StringUtils.isNotBlank(carTrack.getMatchLane())){
String laneNo = carTrack.getMatchLane().substring(23, 26);
if("100".equals(laneNo)) {
isOk = true;
if (StringUtils.isBlank(ridOut)) {
ridOut = carTrack.getMatchLane().substring(0,23);
}
}
}
if (StringUtils.isNotBlank(ridOut) && carTrack.getCrossing() == Constant.CROSSING) {
isOk = true;
}
if(isOk) {
List<CongestionFrameModel.CarTrack> carTrackRidList = listMap.get(ridOut);
if (carTrackRidList == null) {
carTrackRidList = new ArrayList<>();
}
carTrackRidList.add(carTrack);
listMap.put(ridOut, carTrackRidList);
}
}
return listMap;
}
}
package com.wanji.indicators.event.cross.congestion.funcnew;
import com.alibaba.fastjson.JSONObject;
import com.wanji.indicators.model.event.congestion.CongestionOverflowModel;
import org.apache.flink.api.common.functions.FlatMapFunction;
import org.apache.flink.util.Collector;
public class CongestionToStringFlatMap implements FlatMapFunction<CongestionOverflowModel, String> {
@Override
public void flatMap(CongestionOverflowModel model, Collector<String> collector) throws Exception {
String s = JSONObject.toJSONString(model);
collector.collect(s);
}
}
package com.wanji.indicators.event.cross.congestion.funcnew;
import com.wanji.indicators.constant.Constant;
import com.wanji.indicators.constant.DirectionFromCnToEn;
import com.wanji.indicators.constant.EventType;
import com.wanji.indicators.model.event.congestion.CongestionModel;
import com.wanji.indicators.model.event.congestion.CongestionOverflowModel;
import org.apache.commons.lang3.StringUtils;
import org.apache.flink.api.common.state.ValueState;
import org.apache.flink.api.common.state.ValueStateDescriptor;
import org.apache.flink.api.java.tuple.Tuple;
import org.apache.flink.configuration.Configuration;
import org.apache.flink.streaming.api.functions.KeyedProcessFunction;
import org.apache.flink.util.Collector;
/**
* 2022/1/12 17:48
*
* @auther fengyi
*/
public class CongestionValueStateKeyedProcess extends KeyedProcessFunction<Tuple, CongestionModel, CongestionOverflowModel> {
private ValueState<CongestionModel> valueState;
@Override
public void open(Configuration parameters) {
valueState = getRuntimeContext().getState(new ValueStateDescriptor<>("congestionOverFlowValueState_1111III_ox",CongestionModel.class));
}
@Override
public void processElement(CongestionModel congestionModel, Context context, Collector<CongestionOverflowModel> collector) throws Exception {
CongestionModel value = valueState.value();
if (value == null) {
CongestionOverflowModel model = new CongestionOverflowModel();
model.setCrossId(congestionModel.getCrossId());
model.setRid(congestionModel.getRidIn());
model.setRidOut(congestionModel.getRidOut());
model.setTrackId(0);
model.setEventClass(EventType.EVENT.getName());
model.setTypeCode(EventType.OVERFLOW_CONGESTION.getCode());
model.setEventType(EventType.OVERFLOW_CONGESTION.getName());
model.setStartTime(congestionModel.getStartTime());
model.setEndTime(congestionModel.getEndTime());
model.setTime(congestionModel.getStartTime());
model.setDesc("路口溢出: 路口" + congestionModel.getDirection() + "车辆行驶缓慢,疑似路口溢出。");
model.setRecoveryCross(congestionModel.getRecoveryCross());
if (StringUtils.isNotBlank(congestionModel.getDirection())) {
String dirCnDesc = congestionModel.getDirection();
String dirCn = dirCnDesc.substring(0,dirCnDesc.length()-2);
String dirEn = DirectionFromCnToEn.getEnDir(dirCn);
model.setDescEn("Overflow congestion: vehicles at the "+dirEn+" exit of the intersection drive slowly, which is suspected of overflow congestion");
model.setPlateNumber(congestionModel.getDirection());
} else {
model.setPlateNumber("路口溢出");
}
model.setVehicleType("");
model.setX(congestionModel.getLng());
model.setY(congestionModel.getLat());
model.setLocation(new double[]{congestionModel.getLng(), congestionModel.getLat()});
model.setDuration(congestionModel.getDuration());
model.setDir(congestionModel.getDirection());
model.setPictureTime1(model.getStartTime() - 3000L);
model.setPictureTime2(model.getStartTime());
model.setPictureTime3(model.getStartTime() + 3000L);
model.setCheckOutTime(model.getDuration());
model.setId(model.getCrossId() + Constant.MARK + model.getRidOut() + Constant.MARK + model.getTypeCode() + Constant.MARK + model.getStartTime());
collector.collect(model);
valueState.update(congestionModel);
context.timerService().registerProcessingTimeTimer(System.currentTimeMillis() + 7200000L);
}
}
@Override
public void onTimer(long timestamp, OnTimerContext ctx, Collector<CongestionOverflowModel> out) throws Exception {
valueState.clear();
}
}
package com.wanji.indicators.event.cross.deadlock;
import com.alibaba.fastjson.JSONObject;
import com.wanji.indicators.event.cross.deadlock.func.*;
import com.wanji.indicators.model.BaseEventResultModel;
import com.wanji.indicators.model.CrossFrameModel;
import com.wanji.indicators.model.FrameModel;
import com.wanji.indicators.model.event.deadlock.CrossDeadlockResultModel;
import com.wanji.indicators.model.event.deadlock.DeadLockFrameModel;
import com.wanji.indicators.sink.EventFileSink;
import com.wanji.indicators.source.ConflictTurnSource;
import com.wanji.indicators.util.PropertiesHelper;
import org.apache.flink.api.common.functions.FlatMapFunction;
import org.apache.flink.api.common.serialization.SimpleStringSchema;
import org.apache.flink.streaming.api.datastream.DataStream;
import org.apache.flink.streaming.api.datastream.SingleOutputStreamOperator;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.connectors.kafka.FlinkKafkaProducer;
import org.apache.flink.streaming.connectors.kafka.internals.KeyedSerializationSchemaWrapper;
import org.apache.flink.util.Collector;
import org.springframework.beans.BeanUtils;
import java.io.Serializable;
import java.util.Properties;
/**
* 死锁监测
*
* @author fengyi
*/
public class DeadlockEventMainNew implements Serializable {
private StreamExecutionEnvironment env;
private PropertiesHelper instance;
private Properties p;
private String path;
//本地调试设为true输出结果保存到文件
private boolean isDebug = false;
private DeadlockEventMainNew(StreamExecutionEnvironment env, String path, boolean isDebug) {
this.env = env;
this.instance = PropertiesHelper.getInstance();
this.p = instance.getProperties();
this.path = path;
this.isDebug = isDebug;
}
private DeadlockEventMainNew(StreamExecutionEnvironment env) {
this.env = env;
this.instance = PropertiesHelper.getInstance();
this.p = instance.getProperties();
}
public static DeadlockEventMainNew init(StreamExecutionEnvironment env, String path, boolean isDebug) {
return new DeadlockEventMainNew(env, path, isDebug);
}
public static DeadlockEventMainNew init(StreamExecutionEnvironment env) {
return new DeadlockEventMainNew(env);
}
public void run(DataStream<CrossFrameModel> thinningDataStream) {
SingleOutputStreamOperator<CrossFrameModel> time = thinningDataStream
.keyBy(CrossFrameModel::getCrossId)
.countWindow(3)
.maxBy("time");
//解析数据
SingleOutputStreamOperator<DeadLockFrameModel> frameModelFilter = time
.flatMap(new DeadlockFlatMap())
.setParallelism(1)
.name("路口死锁-解析数据");
//处理RID挂接、车道功能转换
SingleOutputStreamOperator<DeadLockFrameModel> ridFuncProcess = frameModelFilter
.keyBy(DeadLockFrameModel::getCrossId)
.process(new DeadlockCheckDataKeyedProcess())
.setParallelism(1)
.name("路口死锁-处理RID挂接、车道功能转换");
//加载冲突相位信息
SingleOutputStreamOperator<DeadLockFrameModel> loadConflictSourceProcess = ridFuncProcess
.connect(env.addSource(new ConflictTurnSource()).broadcast())
.flatMap(new DeadlockConflictSlotCoFlatMap())
.setParallelism(1)
.name("路口死锁-进口转向关联的冲突转向");
//冲突方向检测
SingleOutputStreamOperator<DeadLockFrameModel> conflictDireProcess = loadConflictSourceProcess
.keyBy(DeadLockFrameModel::getCrossId)
.process(new DeadlockConflictCheckKeyedProcess())
.setParallelism(1)
.name("路口死锁-转向冲突线检测");
//死锁检测
SingleOutputStreamOperator<CrossDeadlockResultModel> deadlockCheckProcess = conflictDireProcess
.keyBy(DeadLockFrameModel::getCrossId)
.process(new DeadlockStopCheckKeyedProcess())
.setParallelism(1)
.name("路口死锁-死锁检测");
//路口死锁-逻辑去重
SingleOutputStreamOperator<CrossDeadlockResultModel> deadlockDistinctProcess = deadlockCheckProcess
.keyBy("crossId", "startTime")
.process(new DeadlockDistinctProcess())
.setParallelism(1)
.name("路口死锁-逻辑去重");
if (isDebug) {
SingleOutputStreamOperator<BaseEventResultModel> resultOutProcess = deadlockDistinctProcess
.flatMap(new FlatMapFunction<CrossDeadlockResultModel, BaseEventResultModel>() {
@Override
public void flatMap(CrossDeadlockResultModel baseEventResultModel, Collector<BaseEventResultModel> collector) throws Exception {
BaseEventResultModel target = new BaseEventResultModel();
BeanUtils.copyProperties(baseEventResultModel, target);
target.setPictureTime1(baseEventResultModel.getStartTime());
target.setPictureTime2(baseEventResultModel.getTime() + baseEventResultModel.getDuration()/2);
target.setPictureTime3(baseEventResultModel.getEndTime());
collector.collect(target);
}
})
.setParallelism(1)
.name("路口死锁-死锁检测");
resultOutProcess.addSink(new EventFileSink(path)).setParallelism(1).name("路口死锁-结果输出至本地文件");
resultOutProcess.print("路口死锁-结果").name("路口死锁-结果打印");
} else {
//输出json
SingleOutputStreamOperator<String> jsonOutProcess = deadlockDistinctProcess
.flatMap(new FlatMapFunction<CrossDeadlockResultModel, String>() {
@Override
public void flatMap(CrossDeadlockResultModel baseEventResultModel, Collector<String> collector) throws Exception {
BaseEventResultModel target = new BaseEventResultModel();
BeanUtils.copyProperties(baseEventResultModel, target);
target.setPictureTime1(baseEventResultModel.getStartTime());
target.setPictureTime2(baseEventResultModel.getTime() + baseEventResultModel.getDuration()/2);
target.setPictureTime3(baseEventResultModel.getEndTime());
collector.collect(JSONObject.toJSONString(target));
}
})
.setParallelism(1)
.name("路口死锁-死锁检测");
/**
* 数据输出 -> kafka
*/
FlinkKafkaProducer<String> kafkaProducer = new FlinkKafkaProducer<>(
p.getProperty("cross.event.data.topic"),
new KeyedSerializationSchemaWrapper<>(new SimpleStringSchema()),
instance.getProducerProperties(),
FlinkKafkaProducer.Semantic.NONE);
jsonOutProcess.addSink(kafkaProducer).setParallelism(1).name("路口死锁-结果输出至kafka");
jsonOutProcess.print("路口死锁-结果").name("路口死锁-结果打印");
}
}
}
package com.wanji.indicators.event.cross.deadlock.func;
import com.wanji.indicators.constant.Constant;
import com.wanji.indicators.model.event.deadlock.DeadLockFrameModel;
import com.wanji.indicators.util.CommonUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.flink.api.common.state.MapState;
import org.apache.flink.api.common.state.MapStateDescriptor;
import org.apache.flink.configuration.Configuration;
import org.apache.flink.streaming.api.functions.KeyedProcessFunction;
import org.apache.flink.util.Collector;
import java.util.*;
/**
* 处理RID挂接、车道功能转换
*/
public class DeadlockCheckDataKeyedProcess extends KeyedProcessFunction<String, DeadLockFrameModel, DeadLockFrameModel> {
private MapState<Integer, DeadLockFrameModel.CarTrack> mapState;
@Override
public void open(Configuration parameters) throws Exception {
mapState = getRuntimeContext().getMapState(new MapStateDescriptor<>("mapStateDeadlock_ridCheck_1", Integer.class, DeadLockFrameModel.CarTrack.class));
}
@Override
public void processElement(DeadLockFrameModel deadLockFrameModel, Context context, Collector<DeadLockFrameModel> collector) throws Exception {
long timeNow = deadLockFrameModel.getTime();
List<DeadLockFrameModel.CarTrack> trackList = deadLockFrameModel.getTrackList();
Map<Integer, DeadLockFrameModel.CarTrack> map = new HashMap<>();
List<DeadLockFrameModel.CarTrack> list = new ArrayList<>();
for (DeadLockFrameModel.CarTrack carTrack : trackList) {
map.put(carTrack.getTrackID(), carTrack);
DeadLockFrameModel.CarTrack carTrackState = mapState.get(carTrack.getTrackID());
String matchLane = carTrack.getMatchLane();
if (StringUtils.isNotBlank(matchLane)) {
if (carTrackState == null) {
carTrack.setEntryLane(matchLane);
carTrack.setRid(carTrack.getMatchLane().substring(0, 23));
carTrack.setLaneFunc(CommonUtil.getLaneFunc(carTrack.getMatchLaneName()));
mapState.put(carTrack.getTrackID(), carTrack);
} else {
carTrack.setMatchLane(carTrackState.getMatchLane());
carTrack.setEntryLane(carTrackState.getEntryLane());
carTrack.setRid(carTrackState.getRid());
carTrack.setLaneFunc(carTrackState.getLaneFunc());
}
} else {
if (carTrackState == null) {
String entryLane = carTrack.getEntryLane();
if (StringUtils.isNotBlank(entryLane)) {
carTrack.setRid(entryLane.substring(0, 23));
carTrack.setLaneFunc(Constant.STRAIGHT_LINE_CODE);
double stopLineDist = carTrack.getStopLineDist();
if (stopLineDist > 0.0 && stopLineDist < 6.0) {
carTrack.setRid(entryLane.substring(0, 23));
carTrack.setLaneFunc(CommonUtil.getLaneFunc(carTrack.getMatchLaneName()));
mapState.put(carTrack.getTrackID(), carTrack);
}
}
} else {
if (StringUtils.isNotBlank(carTrack.getEntryLane())) {
carTrack.setRid(carTrack.getEntryLane().substring(0, 23));
carTrack.setLaneFunc(carTrackState.getLaneFunc());
}
}
}
if (StringUtils.isNotBlank(carTrack.getLaneFunc())) {
list.add(carTrack);
} else {
//补录无车道属性的数据
if (carTrack.getCrossing() == Constant.CROSSING) {
carTrack.setMatchLane(Constant.RID_MARK_LANE);
carTrack.setEntryLane(Constant.RID_MARK_LANE);
carTrack.setRid(Constant.RID_MARK);
carTrack.setLaneFunc(Constant.STRAIGHT_LINE_CODE);
list.add(carTrack);
}
}
}
//清除过期数据
Iterator<DeadLockFrameModel.CarTrack> iterator = mapState.values().iterator();
List<DeadLockFrameModel.CarTrack> listMapState = new ArrayList<>();
while (iterator.hasNext()) {
DeadLockFrameModel.CarTrack next = iterator.next();
listMapState.add(next);
}
for (DeadLockFrameModel.CarTrack next : listMapState) {
int trackID = next.getTrackID();
DeadLockFrameModel.CarTrack carTrack = map.get(trackID);
//查询当前帧数据中没有此trackID 说明该目标 上一帧有 当前帧没有
if (carTrack == null) {
//计算当前此目标与时间差多少毫秒 若超过3秒则清除该目标
long timeX = timeNow - next.getTime();
if (timeX > 3000L) {
mapState.remove(trackID);
}
}
}
//发送数据
if (!list.isEmpty()) {
deadLockFrameModel.setTrackList(list);
collector.collect(deadLockFrameModel);
}
}
}
package com.wanji.indicators.event.cross.deadlock.func;
import com.wanji.indicators.constant.Constant;
import com.wanji.indicators.model.ConfigModel;
import com.wanji.indicators.model.event.deadlock.DeadLockFrameModel;
import com.wanji.indicators.util.PtInPolyUtil;
import org.apache.flink.configuration.Configuration;
import org.apache.flink.streaming.api.functions.KeyedProcessFunction;
import org.apache.flink.util.Collector;
import java.util.*;
import java.util.stream.Collectors;
/**
* 检测是否存在冲突运行的车辆
*/
public class DeadlockConflictCheckKeyedProcess extends KeyedProcessFunction<String, DeadLockFrameModel, DeadLockFrameModel> {
@Override
public void open(Configuration parameters) {
}
@Override
public void processElement(DeadLockFrameModel deadLockFrameModel, Context context, Collector<DeadLockFrameModel> collector) throws Exception {
ConfigModel configModel = deadLockFrameModel.getConfigModel();
long nowTime = deadLockFrameModel.getTime();
List<DeadLockFrameModel.CarTrack> trackList = deadLockFrameModel.getTrackList();
List<DeadLockFrameModel.CarTrack> conflictTrackList = new ArrayList<>();
//冲突基础数据key:rid-turn
Map<String, List<Map<String, Object>>> conflictMap = deadLockFrameModel.getConflictSlotMap();
//按RID分组
Map<String, List<DeadLockFrameModel.CarTrack>> groupList = trackList.stream().collect(Collectors.groupingBy(o -> o.getRid()));
if (groupList.size() >= 2) {
//按RID+转向分组
Map<String, List<DeadLockFrameModel.CarTrack>> ridTurnCarList = new HashMap<>();
for (Map.Entry<String, List<DeadLockFrameModel.CarTrack>> entry : groupList.entrySet()) {
String rid = entry.getKey();
List<DeadLockFrameModel.CarTrack> value = entry.getValue();
for (DeadLockFrameModel.CarTrack ridCar : value) {
String laneFunc = ridCar.getLaneFunc();
String[] sps = laneFunc.split(Constant.COMMA);
for (String func : sps) {
String ridTurnKey = null;
if (func.contains(Constant.LEFT_TURN_CODE)) {
ridTurnKey = rid + Constant.MARK + Constant.LEFT_TURN_CODE;
} else if (func.contains(Constant.STRAIGHT_LINE_CODE)) {
ridTurnKey = rid + Constant.MARK + Constant.STRAIGHT_LINE_CODE;
}
List<DeadLockFrameModel.CarTrack> tmplist = ridTurnCarList.get(ridTurnKey);
if (Objects.isNull(tmplist)) {
tmplist = new ArrayList<>();
}
tmplist.add(ridCar);
ridTurnCarList.put(ridTurnKey, tmplist);
}
}
}
for (Map.Entry<String, List<DeadLockFrameModel.CarTrack>> entry : ridTurnCarList.entrySet()) {
String ridTurnKey = entry.getKey();
//冲突进口及转向
List<Map<String, Object>> maplist = conflictMap.get(ridTurnKey);
if (Objects.nonNull(maplist)) {
for (Map<String, Object> cmap : maplist) {
String rid = cmap.get("f_rid").toString();
String turn = cmap.get("turn_dir_no").toString();
String ckey = rid + Constant.MARK + turn;
//检测冲突方向是否有车辆
boolean isMatched = ridTurnCarList.containsKey(ckey);
if (isMatched) {
List<DeadLockFrameModel.CarTrack> carList = entry.getValue();
List<DeadLockFrameModel.CarTrack> carConflictList = ridTurnCarList.get(ckey);
long curDirStopSize = carList.stream().filter(o -> o.getSpeed() < configModel.getDeadlockStopCarSpeed()).count();
long conflictDirStopSize = carConflictList.stream().filter(o -> o.getSpeed() < configModel.getDeadlockStopCarSpeed()).count();
double minDist = this.calculateConlictCarMinDist(carList, carConflictList);
long conflictMinStopCarNums = configModel.getDeadlockConflictMinStopCarNums();
long conflictCarMaxDist = configModel.getDeadlockConflictCarMaxDistance();
//每个冲突方向至少停车数量,所有冲突车辆间最小距离满足阈值
if (curDirStopSize >= conflictMinStopCarNums && conflictDirStopSize >= conflictMinStopCarNums && minDist < conflictCarMaxDist) {
conflictTrackList.addAll(carList);
}
}
}
}
}
}
deadLockFrameModel.setTrackList(conflictTrackList);
collector.collect(deadLockFrameModel);
}
//计算所有冲突车辆的最小距离
private double calculateConlictCarMinDist(List<DeadLockFrameModel.CarTrack> carList, List<DeadLockFrameModel.CarTrack> carConflictList) {
double minDist = Double.MAX_VALUE;
for (DeadLockFrameModel.CarTrack carTrack1 : carList) {
double x1 = carTrack1.getLng();
double y1 = carTrack1.getLat();
for (DeadLockFrameModel.CarTrack carTrack2 : carConflictList) {
double x2 = carTrack2.getLng();
double y2 = carTrack2.getLat();
double distance = PtInPolyUtil.getDistance(x1, y1, x2, y2);
if (distance < minDist) {
minDist = distance;
}
}
}
return minDist;
}
/**
* 获取key
*
* @param carTrack
* @return
*/
private static String getKey(DeadLockFrameModel.CarTrack carTrack) {
return carTrack.getCrossId() + Constant.MARK + carTrack.getTrackID();
}
}
package com.wanji.indicators.event.cross.deadlock.func;
import com.wanji.indicators.constant.Constant;
import com.wanji.indicators.model.event.deadlock.DeadLockFrameModel;
import org.apache.flink.streaming.api.functions.co.CoFlatMapFunction;
import org.apache.flink.util.Collector;
import java.util.*;
/**
* 2021/11/19 17:31
*
* @auther fengyi
*/
public class DeadlockConflictSlotCoFlatMap implements CoFlatMapFunction<DeadLockFrameModel, Map<String, List<Map<String, Object>>>, DeadLockFrameModel> {
private Map<String, List<Map<String, Object>>> conflictSlotMap = new HashMap<>();
@Override
public void flatMap1(DeadLockFrameModel frameModel, Collector<DeadLockFrameModel> collector) throws Exception {
if (conflictSlotMap != null) {
Map<String, List<Map<String, Object>>> filterMap = new HashMap<>();
Set<String> keys = conflictSlotMap.keySet();
//过滤出当前路口的数据
for (String key : keys) {
String[] sps = key.split(Constant.MARK);
String crossId = sps[2];
if (Objects.equals(crossId, frameModel.getCrossId())) {
String subKey = key.substring(0,key.lastIndexOf(Constant.MARK));
filterMap.put(subKey,conflictSlotMap.get(key));
}
}
frameModel.setConflictSlotMap(filterMap);
collector.collect(frameModel);
}
}
@Override
public void flatMap2(Map<String, List<Map<String, Object>>> sourceMap, Collector<DeadLockFrameModel> collector) throws Exception {
this.conflictSlotMap = sourceMap;
}
}
package com.wanji.indicators.event.cross.deadlock.func;
import com.wanji.indicators.constant.Constant;
import com.wanji.indicators.model.event.deadlock.CrossDeadlockResultModel;
import com.wanji.indicators.util.DateUtil;
import org.apache.flink.api.common.state.ValueState;
import org.apache.flink.api.common.state.ValueStateDescriptor;
import org.apache.flink.api.java.tuple.Tuple;
import org.apache.flink.configuration.Configuration;
import org.apache.flink.streaming.api.functions.KeyedProcessFunction;
import org.apache.flink.util.Collector;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* 2022/1/12 17:48
*
* @auther fengyi
*/
public class DeadlockDistinctProcess extends KeyedProcessFunction<Tuple, CrossDeadlockResultModel, CrossDeadlockResultModel> {
private static final Logger log = LoggerFactory.getLogger(DeadlockDistinctProcess.class);
private ValueState<CrossDeadlockResultModel> valueState;
@Override
public void open(Configuration parameters) {
valueState = getRuntimeContext().getState(new ValueStateDescriptor<>("DeadlockDistinctProcess",CrossDeadlockResultModel.class));
}
@Override
public void processElement(CrossDeadlockResultModel deadlockResult, Context context, Collector<CrossDeadlockResultModel> collector) throws Exception {
CrossDeadlockResultModel value = valueState.value();
if (value == null) {
deadlockResult.setId(deadlockResult.getCrossId() + Constant.MARK + deadlockResult.getCrossId() + Constant.MARK + deadlockResult.getTypeCode() + Constant.MARK + deadlockResult.getStartTime());
log.info("路口发生死锁事件:crossId={},startTime={},endTime={},持续时长:{}ms",deadlockResult.getCrossId(), DateUtil.toDateTime(deadlockResult.getStartTime(),"yyyy-MM-dd HH:mm:ss"),DateUtil.toDateTime(deadlockResult.getEndTime(),"yyyy-MM-dd HH:mm:ss"),deadlockResult.getDuration());
collector.collect(deadlockResult);
valueState.update(deadlockResult);
context.timerService().registerProcessingTimeTimer(System.currentTimeMillis() + 7200000L);
}
}
@Override
public void onTimer(long timestamp, OnTimerContext ctx, Collector<CrossDeadlockResultModel> out) throws Exception {
valueState.clear();
}
}
package com.wanji.indicators.event.cross.deadlock.func;
import com.wanji.indicators.constant.Constant;
import com.wanji.indicators.model.CarTrackModel;
import com.wanji.indicators.model.ConfigModel;
import com.wanji.indicators.model.CrossFrameModel;
import com.wanji.indicators.model.FrameModel;
import com.wanji.indicators.model.event.deadlock.DeadLockFrameModel;
import org.apache.flink.api.common.functions.FlatMapFunction;
import org.apache.flink.util.Collector;
import org.springframework.beans.BeanUtils;
import java.util.ArrayList;
import java.util.List;
/**
* 死锁事件--过滤出路口内轨迹
*/
public class DeadlockFlatMap implements FlatMapFunction<CrossFrameModel, DeadLockFrameModel> {
@Override
public void flatMap(CrossFrameModel frameModel, Collector<DeadLockFrameModel> collector) throws Exception {
List<CarTrackModel> trackList = frameModel.getTrackList();
List<DeadLockFrameModel.CarTrack> list = new ArrayList<>();
ConfigModel configModel = frameModel.getConfigModel();
if (configModel.getThreeColorAlarmIsOpen() == Constant.OPEN) {
for (CarTrackModel carTrack : trackList) {
if (/*carTrack.getObjectType() == Constant.VEHICLE
&& carTrack.getCrossing() == Constant.CROSSING
&& carTrack.getStopLineDist() < 0
&& carTrack.getAreaDist() > 8*/
true
) {
DeadLockFrameModel.CarTrack car = new DeadLockFrameModel.CarTrack();
BeanUtils.copyProperties(carTrack, car);
list.add(car);
}
}
DeadLockFrameModel model = new DeadLockFrameModel();
model.setCrossId(frameModel.getCrossId());
model.setTime(frameModel.getGlobalTimeStamp());
model.setTrackList(list);
model.setRidTurnLampList(frameModel.getRidTurnLampList());
model.setConfigModel(frameModel.getConfigModel());
collector.collect(model);
}
}
}
package com.wanji.indicators.event.cross.deadlock.func;
import com.wanji.indicators.constant.Constant;
import com.wanji.indicators.constant.EventType;
import com.wanji.indicators.model.ConfigModel;
import com.wanji.indicators.model.event.deadlock.CrossDeadLockStatusModel;
import com.wanji.indicators.model.event.deadlock.CrossDeadlockResultModel;
import com.wanji.indicators.model.event.deadlock.DeadLockFrameModel;
import org.apache.flink.api.common.state.MapState;
import org.apache.flink.api.common.state.MapStateDescriptor;
import org.apache.flink.configuration.Configuration;
import org.apache.flink.streaming.api.functions.KeyedProcessFunction;
import org.apache.flink.util.Collector;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
/**
* 检测是否存在冲突运行的车辆
*/
public class DeadlockStopCheckKeyedProcess extends KeyedProcessFunction<String, DeadLockFrameModel, CrossDeadlockResultModel> {
private static final Logger log = LoggerFactory.getLogger(DeadlockStopCheckKeyedProcess.class);
private MapState<String, CrossDeadLockStatusModel> mapState;
private MapState<String, CrossDeadlockResultModel> resultMapState;
@Override
public void open(Configuration parameters) {
mapState = getRuntimeContext().getMapState(new MapStateDescriptor<>("mapStateDeadlock_stop_1", String.class, CrossDeadLockStatusModel.class));
resultMapState = getRuntimeContext().getMapState(new MapStateDescriptor<>("mapStateDeadlock_result_1", String.class, CrossDeadlockResultModel.class));
}
@Override
public void processElement(DeadLockFrameModel deadLockFrameModel, Context context, Collector<CrossDeadlockResultModel> collector) throws Exception {
ConfigModel configModel = deadLockFrameModel.getConfigModel();
long nowTime = deadLockFrameModel.getTime();
List<DeadLockFrameModel.CarTrack> conflictTrackList = deadLockFrameModel.getTrackList();
//去重
conflictTrackList = conflictTrackList.stream().distinct().collect(Collectors.toList());
List<String> ridList = conflictTrackList.stream().map(DeadLockFrameModel.CarTrack::getRid).distinct().collect(Collectors.toList());
int allSize = conflictTrackList.size();
//停止车辆数
List<DeadLockFrameModel.CarTrack> stopList = conflictTrackList.stream().filter(o -> o.getSpeed() < configModel.getDeadlockStopCarSpeed()).collect(Collectors.toList());
double stopCarRate = stopList.size() / Double.valueOf(allSize);
if (ridList.size() > 1 && !stopList.isEmpty() && allSize > configModel.getDeadlockMinCarNums() && stopCarRate > configModel.getDeadlockStopCarRate()) {
//log.info(deadLockFrameModel.getCrossId() + "=>满足条件帧时间:" + DateUtil.toDateTime(nowTime, "yyyy-MM-dd HH:mm:ss.SSS"));
long duration = 0;
String effectRids = String.join(",",ridList);
CrossDeadLockStatusModel statusModel = mapState.get(deadLockFrameModel.getCrossId());
if (Objects.isNull(statusModel)) {
statusModel = new CrossDeadLockStatusModel();
statusModel.setCrossId(deadLockFrameModel.getCrossId());
statusModel.setStartTime(nowTime / 1000 * 1000);
statusModel.setEndTime(nowTime);
statusModel.setDuration(0);
statusModel.setTime(nowTime);
statusModel.setEffectRids(effectRids);
mapState.put(deadLockFrameModel.getCrossId(), statusModel);
} else {
duration = nowTime - statusModel.getStartTime();
statusModel.setDuration(duration);
statusModel.setEndTime(nowTime);
statusModel.setTime(nowTime);
mapState.put(deadLockFrameModel.getCrossId(), statusModel);
}
if (duration > configModel.getDeadlockStopCarDuration()) {
CrossDeadlockResultModel resultModel = new CrossDeadlockResultModel();
BeanUtils.copyProperties(statusModel, resultModel);
resultModel.setEventClass(EventType.EVENT.getName());
resultModel.setEventType(EventType.CROSS_DEADLOCK.getName());
resultModel.setTypeCode(EventType.CROSS_DEADLOCK.getCode());
resultModel.setRecoveryCross(stopList.get(0).getRecoveryCross());
resultModel.setDesc("死锁事件:路口内存在冲突方向车辆缓慢运行,疑似出现死锁现象");
resultModel.setDescEn("Deadlock event: there are vehicles running slowly in the conflicting direction at the intersection, which is suspected of deadlock");
CrossDeadlockResultModel disspModel = resultMapState.get(deadLockFrameModel.getCrossId());
if (disspModel == null) {
resultModel.setCheckOutTime(duration);
}else{
resultModel.setCheckOutTime(disspModel.getCheckOutTime());
}
resultModel.setDuration(duration);
//resultModel.setRid(stopList.get(0).getRid());
resultModel.setLocation(new double[]{stopList.get(0).getLng(), stopList.get(0).getLat()});
resultModel.setId(statusModel.getCrossId() + Constant.MARK + statusModel.getCrossId() + Constant.MARK + EventType.CROSS_DEADLOCK.getCode() + Constant.MARK + statusModel.getStartTime());
// List<String> xyList = conflictTrackList.stream().map(o->o.getLng()+","+o.getLat()).distinct().collect(Collectors.toList());
// String xys = String.join(";",xyList);
// Point point = GeomsConvertUtil.genGeometry(xys).getCentroid();
// resultModel.setLocation(new double[]{point.getX(),point.getY()});
resultMapState.put(resultModel.getCrossId(), resultModel);
collector.collect(resultModel);
//log.info("路口发生死锁事件:crossId={},startTime={},endTime={},持续时长:{},停车车辆数:{},总车辆数:{}",resultModel.getCrossId(),DateUtil.toDateTime(resultModel.getStartTime(),"yyyy-MM-dd HH:mm:ss"),DateUtil.toDateTime(resultModel.getEndTime(),"yyyy-MM-dd HH:mm:ss"),duration,stopList.size(),allSize);
} else {
dissp(collector, deadLockFrameModel, configModel, nowTime);
}
} else {//消散清理
//log.info(deadLockFrameModel.getCrossId() + "=>未满足条件帧时间:" + DateUtil.toDateTime(nowTime, "yyyy-MM-dd HH:mm:ss.SSS"));
dissp(collector, deadLockFrameModel, configModel, nowTime);
}
if (!mapState.isEmpty()) {
//缓存清理
Iterable<CrossDeadLockStatusModel> iterable = mapState.values();
List<CrossDeadLockStatusModel> list = StreamSupport.stream(iterable.spliterator(),false).collect(Collectors.toList());
list = list.stream().filter(o->(nowTime-o.getTime())>5000).collect(Collectors.toList());
//缓存超过5秒没有新数据,
for (CrossDeadLockStatusModel model : list){
mapState.remove(model.getCrossId());
}
}
}
//消散清理
private void dissp(Collector<CrossDeadlockResultModel> collector, DeadLockFrameModel deadLockFrameModel, ConfigModel configModel, long nowTime) throws Exception {
CrossDeadlockResultModel disspModel = resultMapState.get(deadLockFrameModel.getCrossId());
if (disspModel != null) {//消散清理
long disspDuration = nowTime - disspModel.getEndTime();
if (disspDuration > configModel.getDeadlockDissipationDuration()) {
mapState.remove(deadLockFrameModel.getCrossId());
resultMapState.remove(deadLockFrameModel.getCrossId());
disspModel.setIsDissipate(1);
collector.collect(disspModel);
//log.info("路口死锁事件消散,清理缓存,当前帧时间{},死锁事件终止i时间{}",DateUtil.toDateTime(nowTime,"yyyy-MM-dd HH:mm:ss"),DateUtil.toDateTime(disspModel.getEndTime(),"yyyy-MM-dd HH:mm:ss"));
}
} else {
CrossDeadLockStatusModel statusModel = mapState.get(deadLockFrameModel.getCrossId());
if (statusModel != null) {
long difTime = Math.abs(nowTime - statusModel.getEndTime());
//未满足持续时间清理状态时间阈值
if (difTime > configModel.getDeadlockStateUnsatisfiedDurationClear()) {
mapState.remove(deadLockFrameModel.getCrossId());
resultMapState.remove(deadLockFrameModel.getCrossId());
}
}
}
}
/**
* 获取key
*
* @param carTrack
* @return
*/
private static String getKey(DeadLockFrameModel.CarTrack carTrack) {
return carTrack.getCrossId() + Constant.MARK + carTrack.getTrackID();
}
}
package com.wanji.indicators.event.cross.stream;
import com.wanji.indicators.constant.Constant;
import com.wanji.indicators.model.CarTrackModel;
import com.wanji.indicators.model.FrameModel;
import com.wanji.indicators.task.track.service.func.CarTrackFlatMap;
import com.wanji.indicators.task.track.service.func.FrameFlatMap;
import com.wanji.indicators.task.travelTime.service.MaxTravelTimeMainNew;
import com.wanji.indicators.util.PropertiesHelper;
import org.apache.flink.api.common.eventtime.WatermarkStrategy;
import org.apache.flink.api.common.functions.FilterFunction;
import org.apache.flink.connector.kafka.source.KafkaSource;
import org.apache.flink.connector.kafka.source.enumerator.initializer.OffsetsInitializer;
import org.apache.flink.connector.kafka.source.reader.deserializer.KafkaRecordDeserializationSchema;
import org.apache.flink.runtime.state.storage.FileSystemCheckpointStorage;
import org.apache.flink.streaming.api.datastream.DataStream;
import org.apache.flink.streaming.api.datastream.SingleOutputStreamOperator;
import org.apache.flink.streaming.api.environment.CheckpointConfig;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.kafka.clients.consumer.OffsetResetStrategy;
import org.apache.kafka.common.serialization.StringDeserializer;
import org.joda.time.DateTime;
import java.util.Arrays;
import java.util.List;
import java.util.Properties;
import java.util.UUID;
public class CalculateTravelTimeMain {
//private static final Logger log = LoggerFactory.getLogger(TrafficEventMain.class);
public static void main(String[] args) {
PropertiesHelper instance = PropertiesHelper.getInstance();
Properties properties = instance.getProperties();
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
env.enableCheckpointing(60*1000);
env.getCheckpointConfig().setTolerableCheckpointFailureNumber(3);
env.getCheckpointConfig().setCheckpointTimeout(10 * 60 * 1000);
env.getCheckpointConfig().setCheckpointStorage(new FileSystemCheckpointStorage(properties.getProperty("check.point.uri")));
//env.setStateBackend(new FsStateBackend(properties.getProperty("check.point.uri")));
env.getCheckpointConfig().setExternalizedCheckpointCleanup(CheckpointConfig.ExternalizedCheckpointCleanup.DELETE_ON_CANCELLATION);
// env.setStateBackend(
// new MemoryStateBackend(MemoryStateBackend.DEFAULT_MAX_STATE_SIZE * 100));
DateTime currentDateTime = new DateTime();
DateTime dateTime = currentDateTime.withMillisOfDay(0).minusHours(-4);
String topic = properties.getProperty("consumer.topic");
KafkaSource<String> source = KafkaSource.<String>builder()
.setProperties(instance.getConsumerProperties())
.setProperty("auto.offset.commit", "true")
.setProperty("auto.commit.interval.ms", "1000")
.setProperty("commit.offsets.on.checkpoint", "true")
.setBootstrapServers(properties.getProperty("bootstrap.servers"))
.setTopics(topic)
.setGroupId(properties.getProperty("consumer.group.id")+"_TRAVEL"+ UUID.randomUUID().toString())
/* 设置起始偏移量有以下几种情况
1.从指定的位置消费:OffsetsInitializer.offsets(Map<TopicPartition, Long> offsets)
2.从最新位置消费(最后一条处):OffsetsInitializer.latest()
3.从最早位置消费(第一条处):OffsetsInitializer.earliest()
4.从上次提交的位置消费:OffsetsInitializer.committedOffsets()
5.新的组,从来没有提交过,再指定一个消费方式:OffsetsInitializer.committedOffsets(OffsetResetStrategy.LATEST)
*/
.setStartingOffsets(OffsetsInitializer.committedOffsets(OffsetResetStrategy.LATEST))
// 从大于等于此时间戳开始的偏移量开始
//.setStartingOffsets(OffsetsInitializer.timestamp(dateTime.getMillis()))
.setDeserializer(KafkaRecordDeserializationSchema.valueOnly(StringDeserializer.class))
.build();
DataStream<String> stream = env
.fromSource(source, WatermarkStrategy.noWatermarks(), "kafka-car-track-source");
SingleOutputStreamOperator<FrameModel> frameModelStream =
stream
.flatMap(new FrameFlatMap())
.setParallelism(1)
.name("轨迹帧数据-JsonToObject");
SingleOutputStreamOperator<CarTrackModel> carTrackModelStream =
frameModelStream.
flatMap(new CarTrackFlatMap())
.setParallelism(1)
.name("轨迹帧数据解析-ToCarTrackModel");
//筛选机动车类型数据
SingleOutputStreamOperator<CarTrackModel> filterStream =
carTrackModelStream.filter(new FilterFunction<CarTrackModel>() {
@Override
public boolean filter(CarTrackModel value) throws Exception {
String motorObjectType = Constant.MOTOR_TYPES;
String[] sps = motorObjectType.split(",");
List<String> typeList = Arrays.asList(sps);
String carType = value.getOriginalType().toString();
if (typeList.contains(carType)){
return true;
}
return false;
}
}).name("筛选机动车数据");
try {
//批量轨迹封装
MaxTravelTimeMainNew.init(env, "indexName").run(filterStream);
env.execute("旅行时间速度计算工作流");
} catch (Exception e) {
e.printStackTrace();
//log.error("交通指标计算任务异常 : " + e);
}
}
}
package com.wanji.indicators.event.cross.stream;
import com.wanji.indicators.constant.Constant;
import com.wanji.indicators.model.CarTrackModel;
import com.wanji.indicators.model.FrameModel;
import com.wanji.indicators.task.track.service.CarRoutePathMainNew;
import com.wanji.indicators.task.track.service.TrackStoreMainNew;
import com.wanji.indicators.task.track.service.func.CarTrackFlatMap;
import com.wanji.indicators.task.track.service.func.FrameFlatMap;
import com.wanji.indicators.util.PropertiesHelper;
import org.apache.flink.api.common.eventtime.WatermarkStrategy;
import org.apache.flink.api.common.functions.FilterFunction;
import org.apache.flink.connector.kafka.source.KafkaSource;
import org.apache.flink.connector.kafka.source.enumerator.initializer.OffsetsInitializer;
import org.apache.flink.connector.kafka.source.reader.deserializer.KafkaRecordDeserializationSchema;
import org.apache.flink.runtime.state.storage.FileSystemCheckpointStorage;
import org.apache.flink.streaming.api.datastream.DataStream;
import org.apache.flink.streaming.api.datastream.SingleOutputStreamOperator;
import org.apache.flink.streaming.api.environment.CheckpointConfig;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.kafka.clients.consumer.OffsetResetStrategy;
import org.apache.kafka.common.serialization.StringDeserializer;
import org.joda.time.DateTime;
import java.util.Arrays;
import java.util.List;
import java.util.Properties;
public class TrackAndRouteMain {
//private static final Logger log = LoggerFactory.getLogger(TrafficEventMain.class);
public static void main(String[] args) {
//批量轨迹es index,逗号分割:esIndexName,windowTime
String indexName = args[0];
String indexName1 = args[1];
// ParameterTool parameter = ParameterTool.fromArgs(args);
// String indexName = parameter.get("Track_ES_IndexName");
// String indexName1 = parameter.get("Route_ES_IndexName");
PropertiesHelper instance = PropertiesHelper.getInstance();
Properties properties = instance.getProperties();
String topic = properties.getProperty("consumer.topic");
if (args.length>2){
topic = args[2];
}
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
env.enableCheckpointing(60*1000);
env.getCheckpointConfig().setTolerableCheckpointFailureNumber(3);
env.getCheckpointConfig().setCheckpointTimeout(10 * 60 * 1000);
env.getCheckpointConfig().setCheckpointStorage(new FileSystemCheckpointStorage(properties.getProperty("check.point.uri")));
//env.setStateBackend(new FsStateBackend(properties.getProperty("check.point.uri")));
env.getCheckpointConfig().setExternalizedCheckpointCleanup(CheckpointConfig.ExternalizedCheckpointCleanup.DELETE_ON_CANCELLATION);
// env.setStateBackend(
// new MemoryStateBackend(MemoryStateBackend.DEFAULT_MAX_STATE_SIZE * 100));
DateTime currentDateTime = new DateTime();
DateTime dateTime = currentDateTime.withMillisOfDay(0).minusHours(-4);
KafkaSource<String> source = KafkaSource.<String>builder()
.setProperties(instance.getConsumerProperties())
.setProperty("auto.offset.commit", "true")
.setProperty("auto.commit.interval.ms", "1000")
.setProperty("commit.offsets.on.checkpoint", "true")
.setBootstrapServers(properties.getProperty("bootstrap.servers"))
.setTopics(topic)
.setGroupId(properties.getProperty("consumer.group.id"))
/* 设置起始偏移量有以下几种情况
1.从指定的位置消费:OffsetsInitializer.offsets(Map<TopicPartition, Long> offsets)
2.从最新位置消费(最后一条处):OffsetsInitializer.latest()
3.从最早位置消费(第一条处):OffsetsInitializer.earliest()
4.从上次提交的位置消费:OffsetsInitializer.committedOffsets()
5.新的组,从来没有提交过,再指定一个消费方式:OffsetsInitializer.committedOffsets(OffsetResetStrategy.LATEST)
*/
.setStartingOffsets(OffsetsInitializer.committedOffsets(OffsetResetStrategy.LATEST))
// 从大于等于此时间戳开始的偏移量开始
//.setStartingOffsets(OffsetsInitializer.timestamp(dateTime.getMillis()))
.setDeserializer(KafkaRecordDeserializationSchema.valueOnly(StringDeserializer.class))
.build();
DataStream<String> stream = env
.fromSource(source, WatermarkStrategy.noWatermarks(), "kafka-car-track-source");
SingleOutputStreamOperator<FrameModel> frameModelStream =
stream
.flatMap(new FrameFlatMap())
.setParallelism(1)
.name("轨迹帧数据-JsonToObject");
SingleOutputStreamOperator<CarTrackModel> carTrackModelStream =
frameModelStream.
flatMap(new CarTrackFlatMap())
.setParallelism(1)
.name("轨迹帧数据解析-ToCarTrackModel");
//筛选机动车类型数据
SingleOutputStreamOperator<CarTrackModel> filterStream =
carTrackModelStream.filter(new FilterFunction<CarTrackModel>() {
@Override
public boolean filter(CarTrackModel value) throws Exception {
String motorObjectType = Constant.MOTOR_TYPES;
String[] sps = motorObjectType.split(",");
List<String> typeList = Arrays.asList(sps);
String carType = value.getOriginalType().toString();
if (typeList.contains(carType)){
return true;
}
return false;
}
}).name("筛选机动车数据");
try {
//批量轨迹封装
TrackStoreMainNew.init(env, indexName).run(carTrackModelStream);
CarRoutePathMainNew.init(env, indexName1).run(carTrackModelStream);
env.execute("轨迹处理工作流");
} catch (Exception e) {
e.printStackTrace();
//log.error("交通指标计算任务异常 : " + e);
}
}
}
package com.wanji.indicators.event.stream;
import com.wanji.indicators.event.cross.conflictpoint.ConflictEventMain;
import com.wanji.indicators.model.CrossFrameModel;
import com.wanji.indicators.model.FrameModel;
import com.wanji.indicators.source.ConsulConfigSource;
import com.wanji.indicators.source.debug.DebugSourceCarFrame;
import com.wanji.indicators.util.CommonUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.flink.api.common.functions.FilterFunction;
import org.apache.flink.streaming.api.datastream.DataStreamSource;
import org.apache.flink.streaming.api.datastream.SingleOutputStreamOperator;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* 离线计算入口 com.mapabc.project.event.cross.stream.OfflineTestMain
* @author ke.han
*/
public class OfflineTestMain {
private static final Logger log = LoggerFactory.getLogger(OfflineTestMain.class);
public static void main(String[] args) {
//初始化环境
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
env.setParallelism(1);
//加载配置项 并获取工作路径
String path = new CommonUtil().getWorkSpasePath();
String outPath = "d:/flink/out/";
String osName = System.getProperties().getProperty("os.name");
if (StringUtils.isNotBlank(osName) && osName.contains("Windows")) {
//此处是 Windows 配置
} else {
path = "/opt/flink/workspace/";
}
//读取离线数据
DataStreamSource<CrossFrameModel> streamSource = env.addSource(new DebugSourceCarFrame(path));
SingleOutputStreamOperator<CrossFrameModel> thinningStream = streamSource
.keyBy(CrossFrameModel::getCrossId)
.countWindow(1)
.maxBy("globalTimeStamp");
//离线调试模式
boolean isDebug = true;
ConflictEventMain.init(env,outPath,isDebug).run(thinningStream);
try {
env.execute("事故事件测试");
} catch (Exception e) {
log.error("事件测试 - 计算任务异常 : " + e);
}
}
}
package com.wanji.indicators.event.stream;
import com.wanji.indicators.event.cross.conflictpoint.ConflictEventMain;
import com.wanji.indicators.event.stream.func.CrossFrameFlatMap;
import com.wanji.indicators.model.CrossFrameModel;
import com.wanji.indicators.util.PropertiesHelper;
import org.apache.flink.api.common.eventtime.WatermarkStrategy;
import org.apache.flink.connector.kafka.source.KafkaSource;
import org.apache.flink.connector.kafka.source.enumerator.initializer.OffsetsInitializer;
import org.apache.flink.connector.kafka.source.reader.deserializer.KafkaRecordDeserializationSchema;
import org.apache.flink.streaming.api.datastream.DataStream;
import org.apache.flink.streaming.api.datastream.SingleOutputStreamOperator;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.kafka.clients.consumer.OffsetResetStrategy;
import org.apache.kafka.common.serialization.StringDeserializer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.*;
public class TrafficEventMain {
//private static final Logger log = LoggerFactory.getLogger(TrafficEventMain.class);
private static final Logger log = LoggerFactory.getLogger(TrafficEventMain.class);
public static void main(String[] args) {
//初始化配置文件
PropertiesHelper instance = PropertiesHelper.getInstance();
Properties properties = instance.getProperties();
//初始化环境
final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
env.setParallelism(1);
String topic = properties.getProperty("consumer.topic");
KafkaSource<String> source = KafkaSource.<String>builder()
.setProperties(instance.getConsumerProperties())
.setProperty("auto.offset.commit", "true")
.setProperty("auto.commit.interval.ms", "1000")
.setProperty("commit.offsets.on.checkpoint", "true")
.setBootstrapServers(properties.getProperty("bootstrap.servers"))
.setTopics(topic)
.setGroupId(properties.getProperty("consumer.group.id")+"-event")
/* 设置起始偏移量有以下几种情况
1.从指定的位置消费:OffsetsInitializer.offsets(Map<TopicPartition, Long> offsets)
2.从最新位置消费(最后一条处):OffsetsInitializer.latest()
3.从最早位置消费(第一条处):OffsetsInitializer.earliest()
4.从上次提交的位置消费:OffsetsInitializer.committedOffsets()
5.新的组,从来没有提交过,再指定一个消费方式:OffsetsInitializer.committedOffsets(OffsetResetStrategy.LATEST)
*/
.setStartingOffsets(OffsetsInitializer.committedOffsets(OffsetResetStrategy.LATEST))
// 从大于等于此时间戳开始的偏移量开始
//.setStartingOffsets(OffsetsInitializer.timestamp(dateTime.getMillis()))
.setDeserializer(KafkaRecordDeserializationSchema.valueOnly(StringDeserializer.class))
.build();
DataStream<String> streamSource = env
.fromSource(source, WatermarkStrategy.noWatermarks(), "kafka-car-track-source-event");
SingleOutputStreamOperator<CrossFrameModel> thinningDataStream =
streamSource
.flatMap(new CrossFrameFlatMap())
.setParallelism(1)
.name("全域轨迹帧数据-按路口分组输出");
//抽帧
SingleOutputStreamOperator<CrossFrameModel> thinningStream = thinningDataStream
.keyBy(CrossFrameModel::getCrossId)
.countWindow(3)
.maxBy("globalTimeStamp")
.name("数据抽帧");
//路口内冲突点计算
ConflictEventMain.init(env).run(thinningStream);
try {
env.execute("全域安全专题计算");
} catch (Exception e) {
log.error("全域安全专题计算任务异常 : " + e);
}
}
}
package com.wanji.indicators.event.stream.func;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.wanji.indicators.model.*;
import com.wanji.indicators.model.event.confilct.EventCross;
import org.apache.flink.api.common.functions.FlatMapFunction;
import org.apache.flink.util.Collector;
import java.util.*;
public class CrossFrameFlatMap implements FlatMapFunction<String, CrossFrameModel> {
@Override
public void flatMap(String value, Collector<CrossFrameModel> out) throws Exception {
JSONObject jsonObject = JSONObject.parseObject(value);
long dataTime = jsonObject.getLongValue("globalTimeStamp");
JSONArray track = jsonObject.getJSONArray("e1FrameParticipant");
if (!track.isEmpty()) {
Map<String, CrossFrameModel> crossFrameModelMap = new HashMap<>();
for (Object obj : track) {
CarTrackModel carTrack = JSONObject.parseObject(obj.toString(), CarTrackModel.class);
String crossId = carTrack.getRoadnet().getCrossId();
CrossFrameModel crossFrameModel = crossFrameModelMap.get(crossId);
if (Objects.isNull(crossFrameModel)) {
crossFrameModel = new CrossFrameModel();
}
crossFrameModel.setCrossId(crossId);
crossFrameModel.setGlobalTimeStamp(dataTime);
crossFrameModel.getTrackList().add(carTrack);
crossFrameModelMap.put(crossId,crossFrameModel);
}
for (Map.Entry<String,CrossFrameModel> entry : crossFrameModelMap.entrySet()){
out.collect(entry.getValue());
}
}
}
/**
* 计算反向角度
* @param angle
* @return
*/
private static double getBackAngle(double angle) {
if (angle >= 180) {
return angle - 180;
} else {
return angle + 180;
}
}
private static EventCross toEventCross(CarTrackModel carTrack){
EventCross e = new EventCross();
e.setPlateColor(carTrack.getLicenseColor());
e.setVehicleColor(carTrack.getOriginalColor());
e.setTrackID(carTrack.getId());
e.setLng(carTrack.getLongitude());
e.setLat(carTrack.getLatitude());
e.setSpeed(carTrack.getSpeed());
e.setDriveAngle(carTrack.getCourseAngle());
e.setPlateNumber(carTrack.getPicLicense());
e.setVehicleType(carTrack.getOriginalType());
e.setTime(carTrack.getGlobalTimeStamp());
e.setAreaDist(carTrack.getWaitingTurnLaneDist());
e.setTravelTime((long) carTrack.getTravelTime());
return e;
}
}
package com.wanji.indicators.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.wanji.indicators.entity.BaseLaneInfo;
import java.util.List;
import java.util.Map;
import org.apache.ibatis.annotations.Param;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
public interface BaseLaneInfoMapper extends BaseMapper<BaseLaneInfo>{
/**
* 查询路口进口车道、出口车道信息
* 根据条件查询表t_base_lane_info信息
* @param baseLaneInfo
*/
List<BaseLaneInfo> findBaseLaneInfoByCondition(BaseLaneInfo baseLaneInfo);
/**
* 查询路口道路方向坐标、车道坐标,
* @param params
* @return
*/
public List<Map<String,Object>> findCrossLaneInfo(Map<String,Object> params);
List<Map<String,Object>> findCrossLaneInfo(Map<String,Object> params);
}
......
......@@ -5,12 +5,12 @@ import lombok.Data;
import java.io.Serializable;
/**
* @Author ke.han
* @Author fengyi
* @Date 2020/4/10 19:25
**/
@Data
public class BaseEventResultModel implements Serializable {
String id;
/**
* 路口id
*/
......
......@@ -24,12 +24,6 @@ public class CarTrackModel implements Serializable {
private Integer originalColor;
/*车辆类型*/
private Integer originalType;
/*车辆所有人*/
private String owner;
/*使用性质*/
private Integer function;
/*所有权*/
private Integer ownership;
/*路网数据*/
private RoadNet roadnet;
......@@ -60,11 +54,16 @@ public class CarTrackModel implements Serializable {
private String laneId;
/*渠化ID*/
private String segmentId;
/*是否在路口范围内*/
private int inCrossFlag;
/*车道功能转向*/
private Integer turn=0;
}
/***********扩展属性*********************************/
//路口内旅行时间,单位秒
private Integer travelTime;
private Integer travelTime=0;
//待转区车道长度,单位米
private Double waitingTurnLaneDist;
private Double waitingTurnLaneDist=0D;
}
......@@ -423,4 +423,5 @@ public class ConfigModel implements Serializable {
private long abnormalParkingSpecialTime;
}
package com.wanji.indicators.model;
import com.wanji.indicators.model.event.confilct.EventCross;
import lombok.Data;
import java.io.Serializable;
......@@ -20,4 +21,6 @@ public class ConflictPointModelBase extends BaseEventResultModel implements Seri
private int num;
private EventCross nearTackObj;
}
package com.wanji.indicators.model;
import com.alibaba.fastjson.annotation.JSONField;
import lombok.Data;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
/**
* 单路口帧数据
* @author fengyi
* @date 2023/3/1
* @description
*/
@Data
public class CrossFrameModel implements Serializable {
private String crossId;
private ConfigModel configModel = new ConfigModel();
//路口各进口道灯态数据
private List<CrossRidTurnLampStatusModel> ridTurnLampList = new ArrayList<>();
private String timeStamp;
private Long globalTimeStamp;
private Integer participantNum;
private String orgCode = "";
private List<CarTrackModel> trackList = new ArrayList<>();
}
package com.wanji.indicators.model;
import java.io.Serializable;
public class CrossRidTurnLampStatusModel implements Serializable {
private String rid;
private String lampState;
private int remainTime;
private String turn;
private String type;
public String getRid() {
return rid;
}
public void setRid(String rid) {
this.rid = rid;
}
public String getLampState() {
return lampState;
}
public void setLampState(String lampState) {
this.lampState = lampState;
}
public int getRemainTime() {
return remainTime;
}
public void setRemainTime(int remainTime) {
this.remainTime = remainTime;
}
public String getTurn() {
return turn;
}
public void setTurn(String turn) {
this.turn = turn;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
@Override
public String toString() {
return "CrossRidTurnLampStatusModel{" +
"rid='" + rid + '\'' +
", lampState='" + lampState + '\'' +
", remainTime=" + remainTime +
", turn='" + turn + '\'' +
", type='" + type + '\'' +
'}';
}
}
package com.wanji.indicators.model;
import com.alibaba.fastjson.annotation.JSONField;
import lombok.Data;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
/**
* 全域帧数据
* @author fengyi
* @date 2023/3/1
* @description
......@@ -13,11 +16,16 @@ import java.util.List;
@Data
public class FrameModel implements Serializable {
private ConfigModel configModel = new ConfigModel();
//路口各进口道灯态数据
private List<CrossRidTurnLampStatusModel> ridTurnLampList = new ArrayList<>();
private String timeStamp;
private Long globalTimeStamp;
private Integer participantNum;
private String orgCode = "";
private List<CarTrackModel> e1FrameParticipant;
@JSONField(name="e1FrameParticipant")
private List<CarTrackModel> trackList;
}
......@@ -49,7 +49,7 @@ public class SingleCarTrackListModel implements Serializable {
@JSONField(format="yyyy-MM-dd HH:mm:ss.SSS")
private Date globalEndTime;
//路网数据
private Set<CarTrackModel.RoadNet> roadnets;
private Set<CarTrackModel.RoadNet> roadNets;
//private CarTrackCommonProperty staticProperty;
......
package com.wanji.indicators.model.event;
import java.io.Serializable;
/**
* 2022/2/15 15:08
*
* @auther ke.han
*/
public class ConfigModelDo implements Serializable {
private String crossId;
private int typeCode;
private String key;
private String value;
private int isOpen;
public String getCrossId() {
return crossId;
}
public void setCrossId(String crossId) {
this.crossId = crossId;
}
public int getTypeCode() {
return typeCode;
}
public void setTypeCode(int typeCode) {
this.typeCode = typeCode;
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public int getIsOpen() {
return isOpen;
}
public void setIsOpen(int isOpen) {
this.isOpen = isOpen;
}
@Override
public String toString() {
return "ConfigModelDo{" +
"crossId='" + crossId + '\'' +
", typeCode=" + typeCode +
", key='" + key + '\'' +
", value='" + value + '\'' +
", isOpen=" + isOpen +
'}';
}
}
package com.wanji.indicators.model.event;
import com.wanji.indicators.util.PtInPolyUtil;
import lombok.Data;
import java.io.Serializable;
import java.util.List;
/**
* 2022/1/19 15:53
*
* @auther ke.han
*/
@Data
public class CongestionAreaDo implements Serializable {
private String crossId;
private String rid;
private int type;
private int typeCode;
private int laneNum;
private String ridInArr;
private String wkt;
private List<PtInPolyUtil.Point> points;
}
package com.wanji.indicators.model.event;
import lombok.Data;
import java.io.Serializable;
@Data
public class CrossShapeDo implements Serializable {
private String rid_in;
private String rid_out;
private int turn_dir;
private String wkt;
private double angle_out;
private double angle_in;
}
package com.wanji.indicators.model.event;
import lombok.Data;
import java.io.Serializable;
@Data
public class CrossShapeModel implements Serializable {
private double length;
private double angle;
private double angleIn;
private String ridIn;
private String ridOut;
private double[] pointOutStart;
private int turnDir;
}
package com.wanji.indicators.model.event;
import lombok.Data;
import java.io.Serializable;
@Data
public class RidDirDo implements Serializable {
private String rid;
private String dir;
private Double angle;
}
package com.wanji.indicators.model.event;
import lombok.Data;
import java.io.Serializable;
@Data
public class WaitingAreaDo implements Serializable {
private String interId;
private String rid;
private String laneId;
private Integer waitingArea;
}
package com.wanji.indicators.model;
package com.wanji.indicators.model.event.confilct;
import lombok.Data;
......@@ -143,7 +143,8 @@ public class EventCross implements Serializable {
private String trackIdNear;
/*路网数据*/
private CarTrackModel.RoadNet roadnet;
//冲突临近对象
private EventCross nearTrackObj;
}
package com.wanji.indicators.model.event.congestion;
import lombok.Data;
import java.io.Serializable;
/**
* 2021/11/19 19:12
*
* @auther ke.han
*/
@Data
public class AccidentCongestionModel implements Serializable {
private String key;
private long startTime;
private long time;
private long duration;
private long traveTimeAvg;
private String ridOut;
private String ridOutDir;
private double lng;
private double lat;
private String recoveryCross;//设备名称
}
package com.wanji.indicators.model.event.congestion;
import com.wanji.indicators.util.PtInPolyUtil;
import lombok.Data;
import java.io.Serializable;
import java.util.List;
/**
* 2022/1/19 15:53
*
* @auther ke.han
*/
@Data
public class CongestionAreaDo implements Serializable {
private String crossId;
private String rid;
private int type;
private int typeCode;
private int laneNum;
private String ridInArr;
private String wkt;
private List<PtInPolyUtil.Point> points;
}
package com.wanji.indicators.model.event.congestion;
import com.wanji.indicators.model.ConfigModel;
import lombok.Data;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
@Data
public class CongestionFrameModel implements Serializable {
private String crossId;
private String rid;
private long time;
private List<CarTrack> trackList;
private ConfigModel configModel;
private Map<String,Integer> congestionInfo;
public CongestionFrameModel() {
}
public CongestionFrameModel(String crossId, long time, List<CarTrack> trackList) {
this.crossId = crossId;
this.time = time;
this.trackList = trackList;
}
public CongestionFrameModel(String crossId, String rid, long time, List<CarTrack> trackList) {
this.crossId = crossId;
this.rid = rid;
this.time = time;
this.trackList = trackList;
}
@Data
public static class CarTrack implements Serializable {
//待转区长度 >> 待转区停止线距离入口车道停止线的距离
private int waitLaneDistance;
//是否拥堵
private boolean isCongestion;
//拥堵开始时间
private long congestionStartTime;
//拥堵结束时间
private long congestionEndTime;
//根据车道功能和进口rid匹配的出口rid
private String ridOut;
//出口rid方向
private String ridOutDir;
//路口当前rid方向行车距离长度
private double crossLength;
private String recoveryCross;//设备名称
/**
* 轨迹数据字段
*/
private String crossId;//: "10I4M0830K0"
private int crossing;// 1
private String lampState;// G
private int trackID;//: 408732
private int objectType;//: 1
private int vehicleColor;//: 4
private int vehicleType;//: 1
private String vehicleBrand;//: "\346\234\254\347\224\260"
private String vehicleSubbrand;//: "\351\233\205\351\230\201"
private String vehicleYearBrand;//: "2003,2004,2007,2008,2010,2011,2012,2013,2014"
private String entryLane;//: "10I6S082VM010I4M0830K0090012"
private String exitLane;//: "10I4M0830K010I360830D0010011"
private String matchLane;//: "10I4M0830K010I360830D0020011"
private String matchLaneName;//: "\350\245\277 1"
private String laneFunc;
private String rid;
private double driveAngle;//: 262.88
private double lat;//: 26.52352862096375
private double lng;//: 106.71488115347212
private int plateColor;//: 6
private String plateNumber;//: "\350\264\265CEA922"
private int plateType;//: 2
private double speed;//: 49.37
private double at;//: -0.09
private double areaDist;//: 61.68
private double stopLineDist;//: -1.0
private double delayTime;//: 0.72
private double travelTime;//: 10.1
private long time;//: 1617279936374
private String plateBgColor;//: "#0000ff"
private String plateTextColor;//: "#ffffff"
}
@Override
public String toString() {
return "FrameModel{" +
"crossId='" + crossId + '\'' +
", time=" + time +
'}';
}
}
package com.wanji.indicators.model.event.congestion;
import com.wanji.indicators.model.ConfigModel;
import lombok.Data;
import java.io.Serializable;
/**
* 2022/1/11 20:36
*
* @auther ke.han
*/
@Data
public class CongestionModel implements Serializable {
private String crossId;
private String ridIn;
private String ridOut;
private String direction;
private long startTime;
private long endTime;
private long duration;
private double lng;
private double lat;
private int eventState;
private int isDissipation;
private ConfigModel configModel;
private String recoveryCross;//设备名称
}
package com.wanji.indicators.model.event.congestion;
import com.wanji.indicators.model.BaseEventResultModel;
import lombok.Data;
import java.io.Serializable;
@Data
public class CongestionOverflowModel extends BaseEventResultModel implements Serializable {
private long duration;
private int eventState;
private String dir;
private String ridOut;
}
package com.wanji.indicators.model.event.congestion;
import lombok.Data;
import java.io.Serializable;
@Data
public class CrossShapeDo implements Serializable {
private String rid_in;
private String rid_out;
private int turn_dir;
private String wkt;
private double angle_out;
private double angle_in;
}
package com.wanji.indicators.model.event.congestion;
import lombok.Data;
import java.io.Serializable;
@Data
public class CrossShapeModel implements Serializable {
private double length;
private double angle;
private double angleIn;
private String ridIn;
private String ridOut;
private double[] pointOutStart;
private int turnDir;
}
package com.wanji.indicators.model.event.congestion;
import lombok.Data;
import java.io.Serializable;
/**
* 2022/1/12 3:02
*
* @auther ke.han
*/
@Data
public class IsCongestionModel implements Serializable {
private double lng;
private double lat;
private String ridOut;
private String ridOutDir;
private boolean isCongestion;
}
package com.wanji.indicators.model.event.deadlock;
import lombok.Data;
import java.io.Serializable;
@Data
public class CrossDeadLockStatusModel implements Serializable {
private String crossId;
private String rid;
private long time;
/**
* 事件开始事件
*/
private long startTime;
/**
* 事件结束事件
*/
private long endTime;
/**
* 持续事件
*/
private long duration;
/**
* 坐标
*/
private double [] location;
/**
* 唯一id
*/
private String id;
/**
* 三色预警状态
*/
private int eventState;
/**
* 影响的rid,多个以逗号分割
*/
private String effectRids="";
}
package com.wanji.indicators.model.event.deadlock;
import lombok.Data;
import java.io.Serializable;
@Data
public class CrossDeadlockResultModel extends CrossDeadLockStatusModel implements Serializable {
/**
* 事件标识
*/
private String eventClass;
/**
* 事件类型
*/
private String eventType;
/**
* 事件类型编码
*/
private int typeCode;
/**
* 事件信息
*/
private String desc;
/**
* 事件信息 - 英文
*/
private String descEn;
/**
* 事件检出时间
*/
private long checkOutTime;
/**
* 路口名称
*/
private String recoveryCross;
/**
* 是否消散 0否 1是
*/
private int isDissipate;
}
package com.wanji.indicators.model.event.deadlock;
import com.wanji.indicators.model.ConfigModel;
import com.wanji.indicators.model.CrossRidTurnLampStatusModel;
import lombok.Data;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 2021/11/9 14:53
*
* @auther ke.han
*/
@Data
public class DeadLockFrameModel implements Serializable {
private int accidentType;
private String crossId;
private String rid;
private long time;
private List<CarTrack> trackList;
private List<CarTrack> conflictTrackList;
private Map<String,Integer> congestionInfo;
private ConfigModel configModel;
//路口各进口道灯态数据
private List<CrossRidTurnLampStatusModel> ridTurnLampList = new ArrayList<>();
//冲突相位信息
private Map<String, List<Map<String, Object>>> conflictSlotMap = new HashMap<>();
public DeadLockFrameModel() {
}
public DeadLockFrameModel(String crossId, long time, List<CarTrack> trackList) {
this.crossId = crossId;
this.time = time;
this.trackList = trackList;
}
public DeadLockFrameModel(String crossId, String rid, long time, List<CarTrack> trackList) {
this.crossId = crossId;
this.rid = rid;
this.time = time;
this.trackList = trackList;
}
@Data
public static class CarTrack implements Serializable {
/**
* 辅助计算字段
*/
//当前帧是否停车 true停车 false行驶
private boolean isStop;
//停车持续时间 单位毫秒
private long stopDuration;
//停车开始时间 时间戳
private long stopTime;
//车辆绕行累计持续时间
private long detourDuration;
//绕行车辆数
private int detourNum;
//待转区长度 >> 待转区停止线距离入口车道停止线的距离
private int waitLaneDistance;
//是否拥堵
private boolean isCongestion;
//拥堵开始时间
private long congestionStartTime;
//拥堵结束时间
private long congestionEndTime;
//拥堵区域出口rid
private String congestionOutRid;
//是否紧急制动
private boolean isEmergencyBraking;
//紧急制动最大加速度
private double emergencyBrakingAt;
//紧急制动车速
private double emergencyBrakingSpeed;
//ttc碰撞预警
private boolean isTTC;
//ttc碰撞预警时的车速
private double ttcSpeed;
//ttc检测到的相交车辆trackId
private int ttcTrackId;
//事故车辆组合后匹配的最近距离trackId
private int accidentTrackId;
//事故车辆组合后与其他车辆的距离
private double accidentDis;
//停车轨迹稳定持续时间
private long stopStableDuration;
//停车时间阈值
private long checkTime;
//是否绿灯停车
private boolean isGreenStop;
//绿灯停车持续时间
private long greenStopDuration;
//绿灯停车开始时间
private long greenStopStartTime;
//分组key = crossId + trackId
private String key;
//key:frid value:右转出口道可进入的其他方向进口道,格式:rid;turn_dir_no
private Map<String,String> ridTurnRefMap = new HashMap<>();
//三色预警蓝色预警开关
private String isOpenBlue;
/**
* 轨迹数据字段
*/
private String crossId;//: "10I4M0830K0"
private int crossing;// 1
private String lampState;// G
private int trackID;//: 408732
private int objectType;//: 1
private int vehicleColor;//: 4
private int vehicleType;//: 1
private String vehicleBrand;//: "\346\234\254\347\224\260"
private String vehicleSubbrand;//: "\351\233\205\351\230\201"
private String vehicleYearBrand;//: "2003,2004,2007,2008,2010,2011,2012,2013,2014"
private String entryLane;//: "10I6S082VM010I4M0830K0090012"
private String exitLane;//: "10I4M0830K010I360830D0010011"
private String matchLane;//: "10I4M0830K010I360830D0020011"
private String matchLaneName;//: "\350\245\277 1"
private String laneFunc;
private String rid;
private double driveAngle;//: 262.88
private double lat;//: 26.52352862096375
private double lng;//: 106.71488115347212
private int plateColor;//: 6
private String plateNumber;//: "\350\264\265CEA922"
private int plateType;//: 2
private double speed;//: 49.37
private double at;//: -0.09
private double areaDist;//: 61.68
private double stopLineDist;//: -1.0
private double delayTime;//: 0.72
private double travelTime;//: 10.1
private long time;//: 1617279936374
private String plateBgColor;//: "#0000ff"
private String plateTextColor;//: "#ffffff
/**
* 路口名称
*/
private String recoveryCross;
}
@Override
public String toString() {
return "FrameModel{" +
"crossId='" + crossId + '\'' +
", time=" + time +
'}';
}
}
......@@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.extension.service.IService;
import com.baomidou.mybatisplus.core.metadata.IPage;
import java.util.List;
import java.util.Map;
/**
* <p>
......@@ -17,4 +18,6 @@ import java.util.List;
public interface BaseLaneInfoService extends IService<BaseLaneInfo> {
public List<BaseLaneInfo> findLaneRidInfo();
public Map<String,BaseLaneInfo> findLaneInfo(String crossId);
}
package com.wanji.indicators.service.impl;
import com.vividsolutions.jts.geom.LineString;
import com.vividsolutions.jts.geom.*;
import com.wanji.indicators.entity.BaseLaneInfo;
import com.wanji.indicators.entity.BaseRidInfo;
import com.wanji.indicators.mapper.BaseLaneInfoMapper;
......@@ -9,10 +9,14 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.wanji.indicators.util.GeomsConvertUtil;
import com.wanji.indicators.util.Tools;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.util.List;
import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;
/**
* <p>
......@@ -25,7 +29,7 @@ import java.util.List;
@Service
public class BaseLaneInfoServiceImpl extends ServiceImpl<BaseLaneInfoMapper, BaseLaneInfo> implements BaseLaneInfoService {
@Autowired
@Resource
private BaseLaneInfoMapper baseLaneInfoMapper;
@Override
......@@ -39,4 +43,32 @@ public class BaseLaneInfoServiceImpl extends ServiceImpl<BaseLaneInfoMapper, Bas
}
return list;
}
@Override
public Map<String,BaseLaneInfo> findLaneInfo(String crossList) {
String[] arr = StringUtils.split(crossList,",");
List<String> crosslist = Arrays.asList(arr);
Map<String, Object> params = new HashMap<>();
params.put("crossList", crosslist);
params.put("type",2);
List<Map<String, Object>> list = this.baseLaneInfoMapper.findCrossLaneInfo(params);
// t.cross_id,t.road_id,t.rid,t.type,t.dir,count(*) lane_num,t.road_wkt
Map<String,BaseLaneInfo> laneInfoMap = new HashMap<>();
for (Map<String, Object> dataMap : list) {
String crossId = Tools.getMapValue("cross_id", dataMap);
String rid = Tools.getMapValue("rid", dataMap);
String laneId = Tools.getMapValue("lane_id", dataMap);
String turn = Tools.getMapValue("turn", dataMap);
BaseLaneInfo baseLaneInfo = new BaseLaneInfo();
baseLaneInfo.setCrossId(crossId);
baseLaneInfo.setRid(rid);
baseLaneInfo.setId(laneId);
baseLaneInfo.setTurn(Integer.valueOf(turn));
laneInfoMap.put(laneId,baseLaneInfo);
}
return laneInfoMap ;
}
}
......@@ -13,6 +13,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import javax.annotation.Resource;
import java.util.List;
/**
......@@ -26,7 +27,7 @@ import java.util.List;
@Service
public class BaseRidInfoServiceImpl extends ServiceImpl<BaseRidInfoMapper, BaseRidInfo> implements BaseRidInfoService {
@Autowired
@Resource
private BaseRidInfoMapper baseRidInfoMapper;
@Override
......
package com.wanji.indicators.sink;
import com.alibaba.fastjson.JSONObject;
import com.wanji.indicators.model.BaseEventResultModel;
import com.wanji.indicators.util.FileUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.flink.streaming.api.functions.sink.SinkFunction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class EventFileSink implements SinkFunction<BaseEventResultModel> {
private static final Logger log = LoggerFactory.getLogger(EventFileSink.class);
private String path;
public EventFileSink(String path) {
this.path = path;
}
@Override
public void invoke(BaseEventResultModel accidentShowModel, Context context) {
if(StringUtils.isNotBlank(path)){
String eventType = accidentShowModel.getEventType();
String plateNumber = accidentShowModel.getPlateNumber();
String timeStr = DateFormatUtils.format(accidentShowModel.getStartTime(),"yyyyMMdd_HHmmss");
String timeStrs = DateFormatUtils.format(accidentShowModel.getStartTime(),"yyyy-MM-dd HH:mm:ss");
FileUtil.writeApend(path + "event_" + eventType + "_" + plateNumber + "_" + timeStr + ".json", JSONObject.toJSONString(accidentShowModel));
log.info("\n{********** The result has been written to the file ********** ==> " + path +
"event_" + eventType + "_" + plateNumber + "_" + timeStrs + ".json}\n");
}
}
}
package com.wanji.indicators.source;
import com.wanji.indicators.constant.Constant;
import org.apache.flink.configuration.Configuration;
import org.apache.flink.streaming.api.functions.source.RichParallelSourceFunction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.*;
/**
* 查询 rid 转向数据 对应的冲突转向
*/
public class ConflictTurnSource extends RichParallelSourceFunction<Map<String, List<Map<String, Object>>>> {
private static final Logger log = LoggerFactory.getLogger(ConflictTurnSource.class);
private volatile boolean running = true;
public void open(Configuration parameters) throws Exception {
}
public static void main(String[] args) {
String s = getQuerySql();
System.out.println(s);
}
private static String getQuerySql() {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("SELECT t1.inter_id,t1.f_rid,t1.t_rid,t1.turn_dir_no as f_turn_dir_no,t2.clash_f_rid,t2.turn_dir_no as t_turn_dir_no ");
stringBuilder.append("FROM ( ");
stringBuilder.append("SELECT b.inter_id,a.f_rid,a.t_rid,b.turn_dir_no,a.clash_f_rid,a.clash_t_rid,a.rr_id,a.clash_rr_id ");
stringBuilder.append("FROM gis_turn_clash a JOIN cross_relation b ");
stringBuilder.append("on a.rr_id=b.rr_id and b.turn_dir_no !=4 ");
stringBuilder.append(") t1 JOIN ( ");
stringBuilder.append("SELECT b.inter_id,a.f_rid,a.t_rid,b.turn_dir_no,a.clash_f_rid,a.clash_t_rid,a.rr_id,a.clash_rr_id ");
stringBuilder.append("FROM gis_turn_clash a JOIN cross_relation b ");
stringBuilder.append("on a.clash_rr_id=b.rr_id and a.f_rid != a.clash_f_rid and b.turn_dir_no !=4 ");
stringBuilder.append(") t2 ON t1.f_rid = t2.f_rid and t1.t_rid=t2.t_rid and t1.clash_f_rid=t2.clash_f_rid and t1.clash_t_rid=t2.clash_t_rid ");
stringBuilder.append("AND t1.inter_id=t2.inter_id ");
stringBuilder.append("JOIN (SELECT DISTINCT inter_id from lane_obj where data_source='2' and inter_id is not null) t3 ");
stringBuilder.append("ON t1.inter_id=t3.inter_id and t2.inter_id=t3.inter_id");
return stringBuilder.toString();
}
@Override
public void run(SourceContext<Map<String, List<Map<String, Object>>>> sourceContext) throws Exception {
//key:rid->turn value:冲突rid及转向
Map<String, List<Map<String, Object>>> retMap = new HashMap<>();
try {
List<HashMap> dataList = null;//new JdbcUtil().excuteQueryToList(HashMap.class, getQuerySql());
if (dataList != null) {
retMap.clear();
for (HashMap<String, Object> map : dataList) {
String crossId = map.get("inter_id").toString();
String rid = map.get("f_rid").toString();
String f_turn_dir_no = map.get("f_turn_dir_no").toString();
String clash_f_rid = map.get("clash_f_rid").toString();//冲突方向rid
String t_turn_dir_no = map.get("t_turn_dir_no").toString();//冲突方向转向
String key = rid + Constant.MARK + f_turn_dir_no + Constant.MARK + crossId;
List<Map<String, Object>> tmplist = retMap.get(key);
if (Objects.isNull(tmplist)) {
tmplist = new ArrayList<>();
}
Map<String, Object> conflictTurnMap = new HashMap<>();
conflictTurnMap.put("f_rid", clash_f_rid);
conflictTurnMap.put("turn_dir_no", t_turn_dir_no);
tmplist.add(conflictTurnMap);
retMap.put(key, tmplist);
sourceContext.collect(retMap);
}
}
} catch (Exception e) {
log.error("查询 rid 冲突信息数据异常: " + e.getMessage(), e);
}
}
@Override
public void cancel() {
running = false;
}
/**
* 理论冲突相位数据,
* 相位标号定义 以北方向为基准定义 1:北直行相位 2:东直行相位 3:南直行相位 4:西直行相位 5:北左转相位 6:东左转 7:南左转 8:西左转
*/
public Map<Integer, List<Integer>> createConflictSlots() {
Map<Integer, List<Integer>> maplist = new HashMap<Integer, List<Integer>>();
for (int i = 1; i < 9; i++) {
Integer sidewalkDir = null;
List<Integer> conflictList = maplist.get(i);
if (Objects.isNull(conflictList)) {
conflictList = new ArrayList<>();
}
if (i < 5) { // 直行相位
// 直行相位的冲突相位点
// 顺时针直行相位
int clockwise = (i + 1) % 4 == 0 ? 4 : (i + 1) % 4;
// 逆时针直行相位
int antiClockWise = (i - 1) % 4 == 0 ? 4 : (i - 1) % 4;
// 对向左转冲突点
int acrossLeft = ((i + 2) % 4 == 0 ? 4 : (i + 2) % 4) + 4;
// 逆时针左转冲突相位点
int antiLeft = ((i - 1) % 4 == 0 ? 4 : (i - 1) % 4) + 4;
conflictList.add(clockwise);
conflictList.add(antiClockWise);
conflictList.add(acrossLeft);
conflictList.add(antiLeft);
} else {// 左转相位冲突相位
// 顺时针直行相位
int antiClockWiseStraight = (i + 1) % 4 == 0 ? 4 : (i + 1) % 4;
// 对向直行冲突点
int acrossStraight = (i + 2) % 4 == 0 ? 4 : (i + 2) % 4;
// 顺时针左转相位
int clockwiseLeft = ((i + 1) % 4 == 0 ? 4 : (i + 1) % 4) + 4;
// 逆时针左转相位
int antiClockWiseLeft = ((i - 1) % 4 == 0 ? 4 : (i - 1) % 4) + 4;
conflictList.add(antiClockWiseStraight);
conflictList.add(acrossStraight);
conflictList.add(clockwiseLeft);
conflictList.add(antiClockWiseLeft);
}
maplist.put(i, conflictList);
}
return maplist;
}
// private static String getQuerySql1() {
// StringBuilder stringBuilder = new StringBuilder();
// stringBuilder.append("SELECT a.inter_id,a.f_rid,a.turn_dir_no,b.dir_4_no, ");
// stringBuilder.append("( ");
// stringBuilder.append("CASE ");
// stringBuilder.append("WHEN b.dir_4_no=3 and turn_dir_no=2 THEN 1 ");
// stringBuilder.append("WHEN b.dir_4_no=3 and turn_dir_no=1 THEN 5 ");
// stringBuilder.append("WHEN b.dir_4_no=4 and turn_dir_no=2 THEN 2 ");
// stringBuilder.append("WHEN b.dir_4_no=4 and turn_dir_no=1 THEN 6 ");
// stringBuilder.append("WHEN b.dir_4_no=1 and turn_dir_no=2 THEN 3 ");
// stringBuilder.append("WHEN b.dir_4_no=1 and turn_dir_no=1 THEN 7 ");
// stringBuilder.append("WHEN b.dir_4_no=2 and turn_dir_no=2 THEN 4 ");
// stringBuilder.append("WHEN b.dir_4_no=2 and turn_dir_no=1 THEN 8 ");
// stringBuilder.append("END ");
// stringBuilder.append(") as slot_no ");
// stringBuilder.append("FROM cross_relation a ");
// stringBuilder.append("JOIN rid b on a.f_rid=b.rid ");
// stringBuilder.append("WHERE turn_dir_no not in (3,4)");
// return stringBuilder.toString();
// }
// public void run1(SourceContext<Map<String, List<Map<String, Object>>>> sourceContext) throws Exception {
// //key:rid->turn value:冲突rid及转向
// Map<String, List<Map<String, Object>>> retMap = new HashMap<>();
// try {
// List<HashMap> dataList = new JdbcUtil().excuteQueryToList(HashMap.class, getQuerySql1());
// Map<Integer, List<Integer>> baseConflictInfo = createConflictSlots();
//
// if (dataList != null && !dataList.isEmpty()) {
// retMap.clear();
// for (HashMap<String, Object> map : dataList) {
// String inter_id = map.get("inter_id").toString();
// String rid = map.get("f_rid").toString();
// String turn_dir_no = map.get("turn_dir_no").toString();
//
// //当前相位编号
// Integer slot_no = Integer.valueOf(map.get("slot_no").toString());
// //冲突相位
// List<Integer> conflictSlot = baseConflictInfo.get(slot_no);
// //冲突相位关联rid等信息
// List<HashMap<String, Object>> conflictSlotList = dataList.stream().filter(m ->Objects.equals(inter_id,m.get("inter_id")) && conflictSlot.contains(Integer.valueOf(m.get("slot_no").toString()))).collect(Collectors.toList());
// if (!conflictSlotList.isEmpty()) {
// String key = rid + Constant.MARK + turn_dir_no;
// List<Map<String, Object>> tmplist = retMap.get(key);
// if (Objects.isNull(tmplist)) {
// tmplist = new ArrayList<>();
// }
// tmplist.addAll(conflictSlotList);
// retMap.put(key, tmplist);
// sourceContext.collect(retMap);
// }
// }
//
//
// }
// } catch (Exception e) {
// log.error("查询 rid 冲突信息数据异常: " + e.getMessage(), e);
// }
// }
}
package com.wanji.indicators.source;
import com.alibaba.fastjson.JSONObject;
import com.google.common.net.HostAndPort;
import com.orbitz.consul.Consul;
import com.orbitz.consul.KeyValueClient;
import com.wanji.indicators.constant.Constant;
import com.wanji.indicators.constant.EventType;
import com.wanji.indicators.model.ConfigModel;
import com.wanji.indicators.model.event.ConfigModelDo;
import com.wanji.indicators.model.event.congestion.CongestionAreaDo;
import com.wanji.indicators.util.PropertiesHelper;
import com.wanji.indicators.util.PtInPolyUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.flink.configuration.Configuration;
import org.apache.flink.streaming.api.functions.source.RichParallelSourceFunction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.*;
import java.util.concurrent.TimeUnit;
/**
* @Author ke.han
* @Date 2020/4/16 19:03
**/
public class ConsulAreaSource extends RichParallelSourceFunction<HashMap<String, Map<String, CongestionAreaDo>>> {
private static final Logger log = LoggerFactory.getLogger(ConsulAreaSource.class);
private Consul client;
private String host = "192.168.11.161";
private int port = 8500;
private int[] typeCodeArr;
private volatile boolean running = true;
public ConsulAreaSource(int[] typeCodeArr) {
this.typeCodeArr = typeCodeArr;
}
public ConsulAreaSource() {}
@Override
public void open(Configuration parameters) throws Exception {
try {
PropertiesHelper instance = PropertiesHelper.getInstance();
Properties properties = instance.getProperties();
String consul_host_properties = properties.getProperty("consul.host");
String consul_port_properties = properties.getProperty("consul.port");
String consul_host_env = System.getenv("CONSUL_HOST");
String consul_port_env = System.getenv("CONSUL_PORT");
if (StringUtils.isNotBlank(consul_host_env)) {
this.host = consul_host_env;
} else {
this.host = consul_host_properties;
}
if (StringUtils.isNotBlank(consul_port_env)) {
this.port = Integer.parseInt(consul_port_env);
} else {
this.port = Integer.parseInt(consul_port_properties);
}
log.info("areaSource consul 服务链接正常: " + host + ":" + port + " ");
} catch (Exception e) {
log.error("consul 服务异常 链接服务异常: " + e.getMessage());
}
}
@Override
public void run(SourceContext<HashMap<String, Map<String, CongestionAreaDo>>> sourceContext) throws Exception {
HashMap<String, Map<String, CongestionAreaDo>> outMap = new HashMap<>();
while (running) {
try {
this.client = Consul.builder().withHostAndPort(HostAndPort.fromParts(host, port)).build();
//通过客户端查询kv值 获取配置
KeyValueClient keyValueClient = client.keyValueClient();
List<String> keys = keyValueClient.getKeys(Constant.CONSUL_EVENT_SETTINGS);
for (String key : keys) {
if (StringUtils.isNotBlank(key) && !key.contains(Constant.CONSUL_EVENT_TEMPLATE) && key.contains(Constant.CONSUL_EVENT_AREA_SET)) {
try {
Optional<String> value = keyValueClient.getValue(key).get().getValueAsString();
if (value.isPresent()) {
List<CongestionAreaDo> dataList = JSONObject.parseArray(value.get(), CongestionAreaDo.class);
for (CongestionAreaDo data : dataList) {
//过滤路口溢出监测区域
if (data.getType() == 1 && data.getTypeCode() == EventType.ABNORMAL_STOP.getCode()) {
Map<String, CongestionAreaDo> congestionAreaDoMap = outMap.get(data.getCrossId());
if (congestionAreaDoMap == null) {
congestionAreaDoMap = new HashMap<>();
}
String wkt = data.getWkt();
if (StringUtils.isNotBlank(wkt)) {
wkt = wkt.replace("POLYGON((","").replace("))","").replace(Constant.COMMA, Constant.SEMICOLON).replace(Constant.SPACE, Constant.COMMA);
String[] wktPointArr = wkt.split(Constant.SEMICOLON);
List<PtInPolyUtil.Point> points = new ArrayList<>();
for (String p : wktPointArr) {
String[] xyArr = p.split(Constant.COMMA);
PtInPolyUtil.Point point = new PtInPolyUtil.Point(Double.valueOf(xyArr[0]), Double.valueOf(xyArr[1]));
points.add(point);
}
data.setPoints(points);
}
congestionAreaDoMap.put(data.getRid(), data);
outMap.put(data.getCrossId(), congestionAreaDoMap);
}
}
}
} catch (Exception e) {
log.error("溢出检测区域 ==>> consul 查询key异常", e.getMessage(), e);
}
}
}
if (outMap.size() > 0) {
sourceContext.collect(outMap);
}
} catch (Exception e) {
log.error("查询溢出检测区域: " + e.getMessage() , e);
} finally {
if (this.client != null) {
this.client.destroy();
}
}
TimeUnit.SECONDS.sleep(60);
}
}
@Override
public void cancel() {
this.running = false;
// client.destroy();
}
private void putData(HashMap<String, ConfigModel> hashMap, List<ConfigModelDo> data) {
for (ConfigModelDo configModelDo : data) {
String crossId = configModelDo.getCrossId();
ConfigModel crossConfigModel = hashMap.get(crossId);
if (crossConfigModel == null) {
crossConfigModel = new ConfigModel();
}
String key = configModelDo.getKey();
String value = configModelDo.getValue();
if (StringUtils.isNotBlank(key) && StringUtils.isNotBlank(value)) {
hashMap.put(crossId, crossConfigModel);
}
}
}
}
package com.wanji.indicators.source;
import com.alibaba.fastjson.JSONObject;
import com.google.common.net.HostAndPort;
import com.orbitz.consul.Consul;
import com.orbitz.consul.KeyValueClient;
import com.wanji.indicators.constant.Constant;
import com.wanji.indicators.model.ConfigModel;
import com.wanji.indicators.model.event.ConfigModelDo;
import com.wanji.indicators.util.PropertiesHelper;
import org.apache.commons.lang3.StringUtils;
import org.apache.flink.configuration.Configuration;
import org.apache.flink.streaming.api.functions.source.RichParallelSourceFunction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.HashMap;
import java.util.List;
import java.util.Optional;
import java.util.Properties;
import java.util.concurrent.TimeUnit;
/**
* @Author ke.han
* @Date 2020/4/16 19:03
**/
public class ConsulConfigSource extends RichParallelSourceFunction<HashMap<String, ConfigModel>> {
private static final Logger log = LoggerFactory.getLogger(ConsulConfigSource.class);
private Consul client;
private String host = "192.168.11.151";
private int port = 8500;
private int[] typeCodeArr;
private volatile boolean running = true;
public ConsulConfigSource(int[] typeCodeArr) {
this.typeCodeArr = typeCodeArr;
}
public ConsulConfigSource() {}
@Override
public void open(Configuration parameters) throws Exception {
try {
PropertiesHelper instance = PropertiesHelper.getInstance();
Properties properties = instance.getProperties();
String consul_host_properties = properties.getProperty("consul.host");
String consul_port_properties = properties.getProperty("consul.port");
String consul_host_env = System.getenv("CONSUL_HOST");
String consul_port_env = System.getenv("CONSUL_PORT");
if (StringUtils.isNotBlank(consul_host_env)) {
this.host = consul_host_env;
} else {
this.host = consul_host_properties;
}
if (StringUtils.isNotBlank(consul_port_env)) {
this.port = Integer.parseInt(consul_port_env);
} else {
this.port = Integer.parseInt(consul_port_properties);
}
} catch (Exception e) {
log.error("consul 服务异常 链接服务异常: " + e.getMessage());
}
}
@Override
public void run(SourceContext<HashMap<String,ConfigModel>> sourceContext) throws Exception {
HashMap<String, ConfigModel> hashMap = new HashMap<>();
while (running) {
try {
this.client = Consul.builder().withHostAndPort(HostAndPort.fromParts(host, port)).build();
//通过客户端查询kv值 获取配置
KeyValueClient keyValueClient = this.client.keyValueClient();
List<String> keys = keyValueClient.getKeys(Constant.CONSUL_EVENT_SETTINGS);
for (String key : keys) {
if (StringUtils.isNotBlank(key) && !key.contains(Constant.CONSUL_EVENT_TEMPLATE) && key.contains(Constant.CONSUL_EVENT_PARAM_SET)) {
try {
Optional<String> value = keyValueClient.getValue(key).get().getValueAsString();
if (value.isPresent()) {
List<ConfigModelDo> data = JSONObject.parseArray(value.get().replaceAll("\\\\",""), ConfigModelDo.class);
putData(hashMap, data);
}
} catch (Exception e) {
log.error("配置查询 ==>> consul 查询kv值异常: key: " + key + " 异常: " + e.getMessage() , e);
}
}
}
if (!hashMap.isEmpty()) {
sourceContext.collect(hashMap);
}
} catch (Exception e) {
log.error("consul 服务异常 查询配置异常: " + e.getMessage() , e);
} finally {
if (this.client != null) {
this.client.destroy();
}
}
TimeUnit.SECONDS.sleep(33);
}
}
@Override
public void cancel() {
this.running = false;
}
private void putData(HashMap<String, ConfigModel> hashMap, List<ConfigModelDo> data) {
for (ConfigModelDo configModelDo : data) {
String crossId = configModelDo.getCrossId();
ConfigModel crossConfigModel = hashMap.get(crossId);
if (crossConfigModel == null) {
crossConfigModel = new ConfigModel();
}
String key = configModelDo.getKey();
String value = configModelDo.getValue();
if (StringUtils.isNotBlank(key) && StringUtils.isNotBlank(value)) {
hashMap.put(crossId, crossConfigModel);
}
}
}
}
package com.wanji.indicators.source;
import com.wanji.indicators.constant.Constant;
import com.wanji.indicators.model.event.CrossShapeDo;
import com.wanji.indicators.model.event.CrossShapeModel;
import com.wanji.indicators.util.PtInPolyUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.flink.streaming.api.functions.source.RichParallelSourceFunction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.HashMap;
import java.util.List;
/**
* 查询 rid 转向数据
*/
public class CrossShapeSource extends RichParallelSourceFunction<HashMap<String, CrossShapeModel>> {
private static final Logger log = LoggerFactory.getLogger(CrossShapeSource.class);
private volatile boolean running = true;
@Override
public void run(SourceContext<HashMap<String, CrossShapeModel>> sourceContext) throws Exception {
HashMap<String, CrossShapeModel> outMap = new HashMap<>();
try {
if (running) {
String sql = "SELECT aa.rid_in,aa.rid_out,aa.turn_dir,aa.wkt,bb.angle AS angle_out,cc.angle AS angle_in " +
" FROM cross_turn_line aa " +
" LEFT JOIN rid bb ON aa.rid_out = bb.rid " +
" LEFT JOIN rid cc ON aa.rid_in = cc.rid " +
" WHERE aa.lane_num > 0";
List<CrossShapeDo> ridLaneNumDos = null;//new JdbcUtil().excuteQueryToList(CrossShapeDo.class, sql);
if (ridLaneNumDos != null && !ridLaneNumDos.isEmpty()) {
outMap.clear();
for (CrossShapeDo data : ridLaneNumDos) {
String rid_in = data.getRid_in();
String wkt = data.getWkt();
int turn_dir = data.getTurn_dir();
String rid_out = data.getRid_out();
double angle_out = data.getAngle_out();
double angle_in = data.getAngle_in();
CrossShapeModel m = new CrossShapeModel();
m.setAngle(angle_out);
m.setAngleIn(angle_in);
m.setRidIn(rid_in);
m.setRidOut(rid_out);
m.setTurnDir(turn_dir);
if (StringUtils.isNotBlank(wkt)) {
String[] wktArr = wkt.split(";");
String[] firstPoint = wktArr[0].split(",");
String[] lastPoint = wktArr[wktArr.length - 1].split(",");
double distance = PtInPolyUtil.getDistance(Double.parseDouble(firstPoint[0]), Double.parseDouble(firstPoint[1]), Double.parseDouble(lastPoint[0]), Double.parseDouble(lastPoint[1]));
m.setLength(distance);
m.setPointOutStart(new double[]{Double.parseDouble(lastPoint[0]), Double.parseDouble(lastPoint[1])});
}
outMap.put(rid_in + Constant.MARK + turn_dir, m);
outMap.put(rid_out + Constant.MARK + turn_dir, m);
}
}
if (outMap.size() > 0) {
sourceContext.collect(outMap);
}
// Thread.sleep(1000*30);
}
} catch (Exception e) {
log.error("查询 rid 转向数据异常: " + e.getMessage(), e);
}
}
@Override
public void cancel() {
running = false;
}
}
package com.wanji.indicators.source;
import com.wanji.indicators.base.env.BeanFactory;
import com.wanji.indicators.entity.BaseLaneInfo;
import com.wanji.indicators.service.BaseLaneInfoService;
import com.wanji.indicators.service.impl.BaseLaneInfoServiceImpl;
import com.wanji.indicators.util.PropertiesHelper;
import org.apache.flink.api.common.ExecutionConfig;
import org.apache.flink.configuration.Configuration;
import org.apache.flink.streaming.api.functions.source.RichParallelSourceFunction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Service;
import java.util.*;
/**
* 车道信息查询
*/
@Service
public class LaneInfoSource extends RichParallelSourceFunction<Map<String, BaseLaneInfo>> {
private static final Logger log = LoggerFactory.getLogger(LaneInfoSource.class);
private volatile boolean running = true;
Properties properties = null;
BaseLaneInfoService baseLaneInfoService;
public void open(Configuration parameters) throws Exception {
super.open(parameters);
ApplicationContext beanConf = new ClassPathXmlApplicationContext("spring-container.xml");
baseLaneInfoService = beanConf.getBean(BaseLaneInfoServiceImpl.class);
PropertiesHelper instance = PropertiesHelper.getInstance();
properties = instance.getProperties();
}
@Override
public void run(SourceContext<Map<String, BaseLaneInfo>> sourceContext) throws Exception {
try {
Map<String, BaseLaneInfo> map = baseLaneInfoService.findLaneInfo(properties.getProperty("full.area.cross.list"));
sourceContext.collect(map);
} catch (Exception e) {
log.error("查询车道信息异常: " + e.getMessage(), e);
}
}
@Override
public void cancel() {
running = false;
}
/**
* 理论冲突相位数据,
* 相位标号定义 以北方向为基准定义 1:北直行相位 2:东直行相位 3:南直行相位 4:西直行相位 5:北左转相位 6:东左转 7:南左转 8:西左转
*/
public Map<Integer, List<Integer>> createConflictSlots() {
Map<Integer, List<Integer>> maplist = new HashMap<Integer, List<Integer>>();
for (int i = 1; i < 9; i++) {
Integer sidewalkDir = null;
List<Integer> conflictList = maplist.get(i);
if (Objects.isNull(conflictList)) {
conflictList = new ArrayList<>();
}
if (i < 5) { // 直行相位
// 直行相位的冲突相位点
// 顺时针直行相位
int clockwise = (i + 1) % 4 == 0 ? 4 : (i + 1) % 4;
// 逆时针直行相位
int antiClockWise = (i - 1) % 4 == 0 ? 4 : (i - 1) % 4;
// 对向左转冲突点
int acrossLeft = ((i + 2) % 4 == 0 ? 4 : (i + 2) % 4) + 4;
// 逆时针左转冲突相位点
int antiLeft = ((i - 1) % 4 == 0 ? 4 : (i - 1) % 4) + 4;
conflictList.add(clockwise);
conflictList.add(antiClockWise);
conflictList.add(acrossLeft);
conflictList.add(antiLeft);
} else {// 左转相位冲突相位
// 顺时针直行相位
int antiClockWiseStraight = (i + 1) % 4 == 0 ? 4 : (i + 1) % 4;
// 对向直行冲突点
int acrossStraight = (i + 2) % 4 == 0 ? 4 : (i + 2) % 4;
// 顺时针左转相位
int clockwiseLeft = ((i + 1) % 4 == 0 ? 4 : (i + 1) % 4) + 4;
// 逆时针左转相位
int antiClockWiseLeft = ((i - 1) % 4 == 0 ? 4 : (i - 1) % 4) + 4;
conflictList.add(antiClockWiseStraight);
conflictList.add(acrossStraight);
conflictList.add(clockwiseLeft);
conflictList.add(antiClockWiseLeft);
}
maplist.put(i, conflictList);
}
return maplist;
}
// private static String getQuerySql1() {
// StringBuilder stringBuilder = new StringBuilder();
// stringBuilder.append("SELECT a.inter_id,a.f_rid,a.turn_dir_no,b.dir_4_no, ");
// stringBuilder.append("( ");
// stringBuilder.append("CASE ");
// stringBuilder.append("WHEN b.dir_4_no=3 and turn_dir_no=2 THEN 1 ");
// stringBuilder.append("WHEN b.dir_4_no=3 and turn_dir_no=1 THEN 5 ");
// stringBuilder.append("WHEN b.dir_4_no=4 and turn_dir_no=2 THEN 2 ");
// stringBuilder.append("WHEN b.dir_4_no=4 and turn_dir_no=1 THEN 6 ");
// stringBuilder.append("WHEN b.dir_4_no=1 and turn_dir_no=2 THEN 3 ");
// stringBuilder.append("WHEN b.dir_4_no=1 and turn_dir_no=1 THEN 7 ");
// stringBuilder.append("WHEN b.dir_4_no=2 and turn_dir_no=2 THEN 4 ");
// stringBuilder.append("WHEN b.dir_4_no=2 and turn_dir_no=1 THEN 8 ");
// stringBuilder.append("END ");
// stringBuilder.append(") as slot_no ");
// stringBuilder.append("FROM cross_relation a ");
// stringBuilder.append("JOIN rid b on a.f_rid=b.rid ");
// stringBuilder.append("WHERE turn_dir_no not in (3,4)");
// return stringBuilder.toString();
// }
// public void run1(SourceContext<Map<String, List<Map<String, Object>>>> sourceContext) throws Exception {
// //key:rid->turn value:冲突rid及转向
// Map<String, List<Map<String, Object>>> retMap = new HashMap<>();
// try {
// List<HashMap> dataList = new JdbcUtil().excuteQueryToList(HashMap.class, getQuerySql1());
// Map<Integer, List<Integer>> baseConflictInfo = createConflictSlots();
//
// if (dataList != null && !dataList.isEmpty()) {
// retMap.clear();
// for (HashMap<String, Object> map : dataList) {
// String inter_id = map.get("inter_id").toString();
// String rid = map.get("f_rid").toString();
// String turn_dir_no = map.get("turn_dir_no").toString();
//
// //当前相位编号
// Integer slot_no = Integer.valueOf(map.get("slot_no").toString());
// //冲突相位
// List<Integer> conflictSlot = baseConflictInfo.get(slot_no);
// //冲突相位关联rid等信息
// List<HashMap<String, Object>> conflictSlotList = dataList.stream().filter(m ->Objects.equals(inter_id,m.get("inter_id")) && conflictSlot.contains(Integer.valueOf(m.get("slot_no").toString()))).collect(Collectors.toList());
// if (!conflictSlotList.isEmpty()) {
// String key = rid + Constant.MARK + turn_dir_no;
// List<Map<String, Object>> tmplist = retMap.get(key);
// if (Objects.isNull(tmplist)) {
// tmplist = new ArrayList<>();
// }
// tmplist.addAll(conflictSlotList);
// retMap.put(key, tmplist);
// sourceContext.collect(retMap);
// }
// }
//
//
// }
// } catch (Exception e) {
// log.error("查询 rid 冲突信息数据异常: " + e.getMessage(), e);
// }
// }
}
package com.wanji.indicators.source;
import com.wanji.indicators.constant.Constant;
import com.wanji.indicators.model.event.RidDirDo;
import com.wanji.indicators.util.PtInPolyUtil;
import org.apache.flink.streaming.api.functions.source.RichParallelSourceFunction;
import java.util.HashMap;
import java.util.List;
/**
* @Author ke.han
* @Date 2020/4/16 19:03
**/
public class RidDirSource extends RichParallelSourceFunction<
HashMap<String, String>> {
private volatile boolean running = true;
@Override
public void run(SourceContext<HashMap<String, String>> out) throws Exception {
HashMap<String, String> outMap = new HashMap<>();
if (running) {
String sql = "SELECT rid,dir_4_no AS dir,angle FROM rid";
List<RidDirDo> ridLaneNumDos = null;//new JdbcUtil().excuteQueryToList(RidDirDo.class, sql);
if (ridLaneNumDos != null && !ridLaneNumDos.isEmpty()) {
outMap.clear();
for (RidDirDo data : ridLaneNumDos) {
String rid = data.getRid();
String dir = data.getDir();
outMap.put(rid, dir);
if(data.getAngle() != null) {
outMap.put(rid + Constant.MARK, PtInPolyUtil.getDir(data.getAngle()));
}
}
}
if (outMap.size() > 0) {
out.collect(outMap);
}
// Thread.sleep(1000*60);
}
}
@Override
public void cancel() {
running = false;
}
}
package com.wanji.indicators.source;
import com.wanji.indicators.model.event.WaitingAreaDo;
import org.apache.flink.streaming.api.functions.source.RichParallelSourceFunction;
import java.util.HashMap;
import java.util.List;
/**
* @Author ke.han
* @Date 2020/4/16 19:03
**/
public class WaitLaneSource extends RichParallelSourceFunction<
HashMap<String, Integer>> {
private volatile boolean running = true;
@Override
public void run(SourceContext<HashMap<String, Integer>> out) {
HashMap<String, Integer> outMap = new HashMap<>();
if (running) {
String sql = "SELECT * FROM cross_flink_settings";
List<WaitingAreaDo> ridLaneNumDos = null;//new JdbcUtil().excuteQueryToList(WaitingAreaDo.class, sql);
if (ridLaneNumDos != null && !ridLaneNumDos.isEmpty()) {
outMap.clear();
for (WaitingAreaDo data : ridLaneNumDos) {
String laneId = data.getLaneId();
Integer waitingArea = data.getWaitingArea();
outMap.put(laneId.trim(), waitingArea);
}
}
if (outMap.size() > 0) {
out.collect(outMap);
}
// Thread.sleep(1000*60);
}
}
@Override
public void cancel() {
running = false;
}
}
package com.wanji.indicators.source.debug;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.wanji.indicators.constant.Constant;
import com.wanji.indicators.model.CarTrackModel;
import com.wanji.indicators.model.CrossFrameModel;
import com.wanji.indicators.model.FrameModel;
import com.wanji.indicators.util.DateUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.flink.streaming.api.functions.source.SourceFunction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.BasicFileAttributes;
import java.time.Instant;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
/**
* 读取本地文件数据源 按每帧读取
*
* @Author ke.han
* @Date 2020/5/29 15:45
**/
public class DebugSourceCarFrame implements SourceFunction<CrossFrameModel> {
private static final Logger log = LoggerFactory.getLogger(DebugSourceCarFrame.class);
private volatile boolean running = true;
private String path;
public DebugSourceCarFrame(String path) {
this.path = path;
}
@Override
public void run(SourceContext<CrossFrameModel> sourceContext) throws Exception {
Properties props = System.getProperties();
String osName = props.getProperty("os.name");
long x = 0;
//清除文件缓存
ConcurrentHashMap<String, CarTrackModel> vehicleInfoCache = new ConcurrentHashMap();
// while (running) {
File files = getFile();
if (files != null) {
TimeUnit.MILLISECONDS.sleep(100);
List<String> sortList = getFileNameArr(files);
for (String str : sortList) {
if (StringUtils.isNotBlank(osName) && !osName.contains("Windows")) {
str = "/" + str;
}
long l = System.currentTimeMillis();
boolean isDelete = false;
File file = new File(path + str.trim());
if (file.exists()) {
isDelete = true;
BufferedReader read = null;
String s = "";
try {
read = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"), 10 * 1024 * 1024);
log.info("Read file: *****| " + str + " |*****");
while ((s = (read.readLine())) != null) {
if (StringUtils.isNotBlank(s)) {
JSONObject jsonObject = JSONObject.parseObject(s);
//FrameModel frameModel = JSONObject.parseObject(s, FrameModel.class);
long dataTime = jsonObject.getLongValue("globalTimeStamp");
JSONArray track = jsonObject.getJSONArray("e1FrameParticipant");
if (!track.isEmpty()) {
x++;
Map<String,CrossFrameModel> crossFrameModelMap = new HashMap<>();
for (Object obj : track) {
CarTrackModel carTrack = JSONObject.parseObject(obj.toString(), CarTrackModel.class);
//补充路口内从哪个进口进入到路口
cacheData(carTrack,vehicleInfoCache);
if (carTrack.getRoadnet().getLaneId().equals("null")){
continue;
}
String crossId = carTrack.getRoadnet().getCrossId();
String laneId = carTrack.getRoadnet().getLaneId();
if (laneId.equals("null") && !crossId.equals("null")){
carTrack.getRoadnet().setInCrossFlag(1);
}
if (Objects.equals("null",crossId)){
crossId = Constant.EMPTY+"_NULL";
}
CrossFrameModel crossFrameModel = crossFrameModelMap.get(crossId);
if (Objects.isNull(crossFrameModel)) {
crossFrameModel = new CrossFrameModel();
}
crossFrameModel.setGlobalTimeStamp(dataTime);
crossFrameModel.setCrossId(crossId);
crossFrameModel.getTrackList().add(carTrack);
crossFrameModelMap.put(crossId,crossFrameModel);
}
for (Map.Entry<String,CrossFrameModel> entry : crossFrameModelMap.entrySet()){
sourceContext.collect(entry.getValue());
}
// log.info(" <<=================||--= 一共计算数据 "+x+" 行 ThreadId: "+Thread.currentThread().getId()+" time:" + frameModel.getTime());
}
}
}
} catch (Exception e) {
e.printStackTrace();
isDelete = false;
TimeUnit.SECONDS.sleep(1);
} finally {
try {
if (read != null) {
read.close();
}
} catch (IOException e) {}
}
}
if (isDelete) {
log.info(" <<=================||--= 一共计算数据 " + x + " 行 =--||=================>> ");
//deleteFile(l, str, file);
}
}
}
// }
}
@Override
public void cancel() {
running = false;
}
private boolean deleteFile(long l , String str , File file) throws InterruptedException {
boolean delete = file.delete();
if (delete) {
long e = System.currentTimeMillis();
log.info(" time consuming: " + (e - l) / 1000 + " s " + (e - l) % 1000 + " ms ==> The file is over: " + str + " clean up.\n");
TimeUnit.MILLISECONDS.sleep(200);
return true;
} else {
return false;
}
}
private List<String> getFileNameArr(File files) {
List<String> fileList = new ArrayList<>();
String[] fileNames = files.list();
if(fileNames != null) {
for (String name : fileNames) {
fileList.add(name);
}
}
return fileList;
}
private File getFile() {
File files = null;
try {
files = new File(path);
} catch (Exception e) {
try {
Thread.sleep(3000L);
} catch (InterruptedException exception) {
}
}
return files;
}
private void cacheData(CarTrackModel carTrack, ConcurrentHashMap<String, CarTrackModel> vehicleInfoCache) {
String crossId = carTrack.getRoadnet().getCrossId();
int trackID = carTrack.getId();
CarTrackModel cache = vehicleInfoCache.get(crossId + trackID);
if (cache==null && !carTrack.getRoadnet().getLaneId().equals("null")) {
carTrack.getRoadnet().setRid(carTrack.getRoadnet().getRid());
carTrack.getRoadnet().setLaneId(carTrack.getRoadnet().getLaneId());
carTrack.getRoadnet().setCrossId(carTrack.getRoadnet().getCrossId());
vehicleInfoCache.put(crossId + trackID, carTrack);
}
if (cache != null) {
if (carTrack.getRoadnet().getLaneId().equals("null")) {
carTrack.getRoadnet().setRid(cache.getRoadnet().getRid());
carTrack.getRoadnet().setLaneId(cache.getRoadnet().getLaneId());
carTrack.getRoadnet().setCrossId(cache.getRoadnet().getCrossId());
carTrack.getRoadnet().setInCrossFlag(1);
vehicleInfoCache.put(crossId + trackID, carTrack);
}
}
}
/**
* 排序
*
* @param list
* @return
*/
public static List<String> getSortList(List<String> list) {
try {
Collections.sort(list, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
long o1x = Long.valueOf(o1.substring(o1.lastIndexOf("_") + 1, o1.indexOf(".")));
long o2x = Long.valueOf(o2.substring(o2.lastIndexOf("_") + 1, o2.indexOf(".")));
if (o1x > o2x) {
return 1;
}
if (o1x == o2x) {
return 0;
}
return -1;
}
});
} catch (Exception e) {
log.error("SortListException:" + e);
return list;
}
return list;
}
public static long getCreationTime(File file) {
if (file == null) {
return System.currentTimeMillis();
}
BasicFileAttributes attr = null;
try {
Path path = file.toPath();
attr = Files.readAttributes(path, BasicFileAttributes.class);
} catch (IOException e) {
e.printStackTrace();
}
// 创建时间
Instant instant = attr.creationTime().toInstant();
// 更新时间
// Instant instant = attr.lastModifiedTime().toInstant();
// 上次访问时间
// Instant instant = attr.lastAccessTime().toInstant();
String format = DateTimeFormatter.ofPattern(DateUtil.YYYY_MM_DD_HH_MM_SS).withZone(ZoneId.systemDefault()).format(instant);
return DateUtil.StringToMillis(format);
}
}
set table.exec.sink.not-null-enforcer=drop;
-- cron:0 0 */1 * * ?
-- 任务名称:EVENT_BIG_CATEGORY_STATISTIC
-- 任务描述:事件大类统计
-- 输出数据表:t_analysis_event_trend_hour、t_analysis_event_trend_day
-- 依赖包:flink-connector-jdbc_2.11-1.14.3.jar、mysql-connector-java-8.0.21.jar
set table.exec.sink.not-null-enforcer=drop;
CREATE TABLE t_event_info(
oid BIGINT NOT NULL,
type STRING,
......@@ -72,6 +77,7 @@ CREATE TABLE t_analysis_event_trend_hour (
'username' = 'root',
'password' = 'Wanji300552'
);
insert into t_analysis_event_trend_hour(category,number,window_start_time,window_end_time,granularity)
SELECT event_category,SUM(event_number),window_start_time,window_end_time,'1h'
FROM t_analysis_event
......
-- cron:0 0/15 * * * ?
-- 任务名称:EVENT_BIG_CATEGORY_STATISTIC
-- 任务描述:1小时粒度事件统计
-- 输出数据表:t_analysis_event
-- 依赖包:flink-connector-jdbc_2.11-1.14.3.jar、mysql-connector-java-8.0.21.jar
set table.exec.sink.not-null-enforcer=drop;
CREATE TABLE t_event_info(
......
-- cron:0 0 */1 * * ?
-- 任务名称:EVENT_BIG_CATEGORY_STATISTIC
-- 任务描述:1小时粒度事件统计
-- 输出数据表:t_analysis_event
-- 依赖包:flink-connector-jdbc_2.11-1.14.3.jar、mysql-connector-java-8.0.21.jar
set table.exec.sink.not-null-enforcer=drop;
CREATE TABLE t_event_info(
......
-- cron:0 0/15 * * * ?
-- 任务名称:EVENT_BIG_CATEGORY_STATISTIC
-- 任务描述:1小时粒度事件统计
-- 输出数据表:t_analysis_event
-- 依赖包:flink-connector-jdbc_2.11-1.14.3.jar、mysql-connector-java-8.0.21.jar
set table.exec.sink.not-null-enforcer=drop;
CREATE TABLE t_event_info(
......
......@@ -45,12 +45,12 @@ CREATE TABLE source_gloabl_lane_cycle_data (
) WITH (
'connector' = 'kafka', -- 使用 kafka connector
'topic-pattern' = 'JN(.*)LanePeriodicData', -- kafka topic
'properties.bootstrap.servers' = '192.168.2.103:9092', -- broker连接信息
'properties.bootstrap.servers' = '37.12.182.31:9092', -- broker连接信息
'properties.group.id' = 't_global_lane_cycle_data_15m', -- 消费kafka的group_id
'properties.enable.auto.commit' = 'true',
'properties.auto.commit.interval.ms' = '1000',
'scan.startup.mode' = 'group-offsets',
-- 'scan.startup.mode' = 'latest-offset', -- 读取数据的位置
-- 'scan.startup.mode' = 'group-offsets',
'scan.startup.mode' = 'latest-offset', -- 读取数据的位置
-- 'scan.startup.mode' = 'earliest-offset',
-- 'scan.startup.mode' = 'group-offsets',
-- 'scan.startup.mode' = 'timestamp', -- 读取数据的位置
......@@ -274,7 +274,7 @@ SELECT tb.cross_id,
tb.lane_no,
tb.turn,
SUM(tb.traffic_flow),
SUM(tb.traffic_flow)/SUM(tb.lane_capacity) lane_saturation,
SUM(tb.traffic_flow)*4/(SUM(tb.lane_capacity)/3) lane_saturation,
AVG(tb.mean_delay),
AVG(tb.mean_v),
MAX(tb.queue_length),
......@@ -308,7 +308,7 @@ SELECT tb.cross_id,
AVG(tb.light_green_finish_queue_length),
AVG(tb.green_light_efficiency),
MAX(tb.lane_saturation_flow_rate),
SUM(tb.lane_capacity),
CAST((SUM(tb.lane_capacity )/3) AS INT) lane_capacity, -- 5分钟周期输出的通行能力的单位是辆/小时,15分钟累加求和以后按时间批次进行平均保持为小时单位,否则相当于3个小时通行能力
AVG(tb.lane_no_stop_rate),
AVG(tb.lane_three_stop_rate),
TUMBLE_START(tb.ts_ltz, INTERVAL '15' MINUTE) start_window_time,
......@@ -380,7 +380,9 @@ create table t_analysis_rid_entrace_indicator
'url' = 'jdbc:mysql://172.17.0.1:3306/holo_roadnet?characterEncoding=UTF-8&serverTimezone=Asia/Shanghai',
'table-name' = 't_analysis_rid_entrace_indicator',
'username' = 'root',
'password' = 'Wanji300552'
'password' = 'Wanji300552',
'sink.buffer-flush.max-rows' = '0',
'sink.buffer-flush.interval' = '1000'
);
-- 进口道指标
insert into t_analysis_rid_entrace_indicator(cross_id,cross_name,rid,rid_dir,traffic_index,capacity,flow,saturation,queue_length,speed,delay_time,stop_num,statistic_time,granularity,ruksj,window_start_time,window_end_time,
......@@ -392,7 +394,7 @@ SELECT tb1.cross_id,tb1.cross_name,tb1.rid,tb1.in_dir,
if(tb1.traffic_index>999,999,tb1.traffic_index),
tb1.lane_capacity,
tb1.traffic_flow,
(tb1.traffic_flow/tb1.lane_capacity) saturation,
(tb1.traffic_flow*4/tb1.lane_capacity) saturation,
tb1.queue_length,
tb1.mean_v,
tb1.mean_delay,
......@@ -438,7 +440,7 @@ SELECT tb1.cross_id,tb1.cross_name,tb1.rid,tb1.in_dir,
FROM (
SELECT tb.cross_id,tb.cross_name,tb.rid,tb.in_dir,
(ifnull(tb.free_speed,80)/avg(tb.mean_v)) as traffic_index,
SUM(tb.lane_capacity) lane_capacity,
CAST((SUM(tb.lane_capacity )/3) AS INT) lane_capacity, -- 5分钟周期输出的通行能力的单位是辆/小时,15分钟累加求和以后按时间批次进行平均保持为小时单位,否则相当于3个小时通行能力
SUM(tb.traffic_flow) traffic_flow,
AVG(tb.lane_saturation) lane_saturation,
MAX(tb.queue_length) queue_length,
......@@ -528,7 +530,9 @@ create table t_analysis_rid_turn_indicators
'url' = 'jdbc:mysql://172.17.0.1:3306/holo_roadnet?characterEncoding=UTF-8&serverTimezone=Asia/Shanghai',
'table-name' = 't_analysis_rid_turn_indicators',
'username' = 'root',
'password' = 'Wanji300552'
'password' = 'Wanji300552',
'sink.buffer-flush.max-rows' = '0',
'sink.buffer-flush.interval' = '1000'
);
create table t_config_lane_flow_coefficient
......@@ -673,7 +677,7 @@ FROM
AVG(light_green_start_queue_length ) light_green_start_queue_length,
AVG(light_green_finish_queue_length ) light_green_finish_queue_length,
CAST(ROUND(MAX( tb.lane_saturation_flow_rate * tb.flow_coefficient )) AS INT) saturation_flow_rate,
CAST(ROUND(SUM( tb.lane_capacity * tb.flow_coefficient )) AS INT) capacity,
CAST(ROUND(SUM( tb.lane_capacity * tb.flow_coefficient )/3) AS INT) capacity,
CAST(ROUND(SUM(traffic_flow_A * tb.flow_coefficient),0) AS INT) traffic_flow_A,
CAST(ROUND(SUM(traffic_flow_B * tb.flow_coefficient),0) AS INT) traffic_flow_B,
CAST(ROUND(SUM(traffic_flow_C * tb.flow_coefficient),0) AS INT) traffic_flow_C,
......@@ -725,31 +729,38 @@ create table t_analysis_cross_indicators
efficiency_index decimal(6,2),
evaluation_grade varchar,
service_level varchar,
traffic_flow_A INT,
traffic_flow_B INT,
traffic_flow_C INT,
PRIMARY KEY (cross_id,granularity,window_end_time) NOT ENFORCED
) WITH (
'connector' = 'jdbc',
'url' = 'jdbc:mysql://172.17.0.1:3306/holo_roadnet?characterEncoding=UTF-8&serverTimezone=Asia/Shanghai',
'table-name' = 't_analysis_cross_indicators',
'username' = 'root',
'password' = 'Wanji300552'
'password' = 'Wanji300552',
'sink.buffer-flush.max-rows' = '0',
'sink.buffer-flush.interval' = '1000'
);
-- 计算路口通过时长占比
CREATE VIEW v_pass_time_rate AS
SELECT tc.cross_id, SUM(tc.free_travel_time) free_travel_time,SUM(tc.travel_time) as travel_time, tc.window_start,tc.window_end
FROM (
SELECT tb.cross_id,
tb.rid,
(tb.ridLength / tb.free_speed) free_travel_time,
(tb.ridLength / if(avg(tb.mean_v)=0,1,avg(tb.mean_v))) travel_time,
window_start, window_end
SELECT
tb.cross_id,
tb.rid,
(tb.ridLength / tb.free_speed) free_travel_time,
(tb.ridLength / if(avg(tb.mean_v)=0,1,avg(tb.mean_v))) travel_time,
window_start,
window_end
FROM TABLE(TUMBLE(TABLE v_kafka_cycle_data,DESCRIPTOR(ts_ltz),INTERVAL '15' MINUTE)) tb
GROUP BY tb.cross_id, tb.cross_name, tb.rid, tb.ridLength, tb.free_speed, window_start, window_end
) tc
GROUP BY tc.cross_id, tc.window_start, tc.window_end
;
insert into t_analysis_cross_indicators(cross_id,cross_name,speed,saturation,stop_num,max_queue_length,ruksj,granularity,avg_delay,capacity,flow,window_start_time,window_end_time,congest_index,no_stop_rate,once_stop_rate,second_stop_rate,three_stop_rate,green_start_max_queue,green_use_rate,hour_flow,efficiency_index,evaluation_grade,service_level)
insert into t_analysis_cross_indicators(cross_id,cross_name,speed,saturation,stop_num,max_queue_length,ruksj,granularity,avg_delay,capacity,flow,window_start_time,window_end_time,congest_index,no_stop_rate,once_stop_rate,second_stop_rate,three_stop_rate,green_start_max_queue,green_use_rate,hour_flow,efficiency_index,traffic_flow_A,traffic_flow_B,traffic_flow_C,evaluation_grade,service_level)
SELECT t.*,
-- 效率等级
(CASE WHEN t.efficiency_index>=7 THEN '1' WHEN t.efficiency_index>=3 THEN '2' ELSE '3' END) evaluation_grade,
......@@ -766,22 +777,28 @@ SELECT t.*,
FROM
(
SELECT t1.cross_id,t1.cross_name,t1.speed,t1.saturation,t1.stop_num,t1.max_queue_length,LOCALTIMESTAMP ruksj,t1.granularity,t1.avg_delay,t1.capacity,t1.flow,t1.start_window_time,t1.end_window_time,t1.congest_index,t1.no_stop_rate,t1.once_stop_rate,t1.second_stop_rate,t1.three_stop_rate,t1.green_start_max_queue,t1.green_use_rate,t1.hour_flow,
(
(t1.flow/t1.capacity) * 10 * 0.2 +
(t1.avg_lane_saturation) * 10 * 0.2 +
(t1.no_stop_rate + t1.once_stop_rate) * 10 * 0.3 +
(t2.free_travel_time / t2.travel_time) * 10 * 0.3
)/4 AS efficiency_index -- 效率指数
ifnull( (
(t1.flow/t1.capacity) * 10 * 0.2 +
(t1.avg_lane_saturation) * 10 * 0.2 +
(t1.no_stop_rate + t1.once_stop_rate) * 10 * 0.3 +
(IFNULL(t2.free_travel_time,1) / IFNULL(t2.travel_time,1)) * 10 * 0.3
),0) AS efficiency_index -- /4 AS efficiency_index
,
t1.traffic_flow_A,
t1.traffic_flow_B,
t1.traffic_flow_C
FROM (
SELECT tb.cross_id,
tb.cross_name,
AVG(tb.mean_v) as speed,
SUM(tb.traffic_flow)/ SUM(tb.lane_capacity) saturation,
AVG(tb.lane_saturation) saturation,
-- (SUM(tb.traffic_flow)*4)/ (SUM(tb.lane_capacity)/3) saturation,
AVG(tb.mean_stops_number) stop_num,
CAST(ROUND(MAX(tb.queue_length),0) AS INT) max_queue_length,
'15m' granularity,
AVG(tb.mean_delay) avg_delay,
SUM(tb.lane_capacity ) capacity,
CAST((SUM(tb.lane_capacity )/3) AS INT) capacity, -- 5分钟周期输出的通行能力的单位是辆/小时,15分钟累加求和以后按时间批次进行平均保持为小时单位,否则相当于3个小时通行能力
SUM(tb.traffic_flow) flow,
TUMBLE_START(tb.ts_ltz, INTERVAL '15' MINUTE) start_window_time,
TUMBLE_END(tb.ts_ltz, INTERVAL '15' MINUTE) end_window_time,
......@@ -793,10 +810,13 @@ FROM
CAST(MAX(tb.light_green_start_queue_length) AS INT) green_start_max_queue,
AVG( tb.green_light_efficiency) green_use_rate,
CAST(AVG(tb.lane_flow_rate) AS INT) hour_flow,
AVG(tb.lane_saturation) avg_lane_saturation
AVG(tb.lane_saturation) avg_lane_saturation,
SUM(tb.traffic_flow_A) traffic_flow_A,
SUM(tb.traffic_flow_B) traffic_flow_B,
SUM(tb.traffic_flow_C) traffic_flow_C
FROM v_kafka_cycle_data tb
group by TUMBLE(tb.ts_ltz, INTERVAL '15' MINUTE),tb.cross_id,tb.cross_name
) t1
FULL JOIN v_pass_time_rate t2 on t1.cross_id=t2.cross_id and t1.start_window_time=t2.window_start and t1.end_window_time=t2.window_end
LEFT JOIN v_pass_time_rate t2 on t1.cross_id=t2.cross_id and t1.start_window_time=t2.window_start and t1.end_window_time=t2.window_end
) t
;
\ No newline at end of file
......@@ -43,12 +43,12 @@ CREATE TABLE source_gloabl_lane_cycle_data (
) WITH (
'connector' = 'kafka', -- 使用 kafka connector
'topic-pattern' = 'JN(.*)LanePeriodicData', -- kafka topic
'properties.bootstrap.servers' = '192.168.2.103:9092', -- broker连接信息
'properties.bootstrap.servers' = '37.12.182.31:9092', -- broker连接信息
'properties.group.id' = 't_global_lane_cycle_data_1h', -- 消费kafka的group_id
'properties.enable.auto.commit' = 'true',
'properties.auto.commit.interval.ms' = '1000',
'scan.startup.mode' = 'group-offsets',
-- 'scan.startup.mode' = 'latest-offset', -- 读取数据的位置
-- 'scan.startup.mode' = 'group-offsets',
'scan.startup.mode' = 'latest-offset', -- 读取数据的位置
-- 'scan.startup.mode' = 'earliest-offset',
-- 'scan.startup.mode' = 'group-offsets',
-- 'scan.startup.mode' = 'timestamp', -- 读取数据的位置
......@@ -272,7 +272,7 @@ SELECT tb.cross_id,
tb.lane_no,
tb.turn,
SUM(tb.traffic_flow),
SUM(tb.traffic_flow)/SUM(tb.lane_capacity) lane_saturation,
SUM(tb.traffic_flow)*4/(SUM(tb.lane_capacity)/12) lane_saturation,
AVG(tb.mean_delay),
AVG(tb.mean_v),
MAX(tb.queue_length),
......@@ -306,7 +306,7 @@ SELECT tb.cross_id,
AVG(tb.light_green_finish_queue_length),
AVG(tb.green_light_efficiency),
MAX(tb.lane_saturation_flow_rate),
SUM(tb.lane_capacity),
CAST((SUM(tb.lane_capacity )/12) AS INT) capacity,
AVG(tb.lane_no_stop_rate),
AVG(tb.lane_three_stop_rate),
TUMBLE_START(tb.ts_ltz, INTERVAL '1' HOUR) start_window_time,
......@@ -378,7 +378,9 @@ create table t_analysis_rid_entrace_indicator
'url' = 'jdbc:mysql://172.17.0.1:3306/holo_roadnet?characterEncoding=UTF-8&serverTimezone=Asia/Shanghai',
'table-name' = 't_analysis_rid_entrace_indicator',
'username' = 'root',
'password' = 'Wanji300552'
'password' = 'Wanji300552',
'sink.buffer-flush.max-rows' = '0',
'sink.buffer-flush.interval' = '1000'
);
-- 进口道指标
insert into t_analysis_rid_entrace_indicator(cross_id,cross_name,rid,rid_dir,traffic_index,capacity,flow,saturation,queue_length,speed,delay_time,stop_num,statistic_time,granularity,ruksj,window_start_time,window_end_time,
......@@ -390,7 +392,7 @@ SELECT tb1.cross_id,tb1.cross_name,tb1.rid,tb1.in_dir,
if(tb1.traffic_index>999,999,tb1.traffic_index),
tb1.lane_capacity,
tb1.traffic_flow,
(tb1.traffic_flow/tb1.lane_capacity) saturation,
(tb1.traffic_flow*4/tb1.lane_capacity) saturation,
tb1.queue_length,
tb1.mean_v,
tb1.mean_delay,
......@@ -436,7 +438,7 @@ SELECT tb1.cross_id,tb1.cross_name,tb1.rid,tb1.in_dir,
FROM (
SELECT tb.cross_id,tb.cross_name,tb.rid,tb.in_dir,
(ifnull(tb.free_speed,80)/avg(tb.mean_v)) as traffic_index,
SUM(tb.lane_capacity) lane_capacity,
CAST((SUM(tb.lane_capacity )/12) AS INT) lane_capacity,
SUM(tb.traffic_flow) traffic_flow,
AVG(tb.lane_saturation) lane_saturation,
MAX(tb.queue_length) queue_length,
......@@ -671,7 +673,7 @@ FROM
AVG(light_green_start_queue_length ) light_green_start_queue_length,
AVG(light_green_finish_queue_length ) light_green_finish_queue_length,
CAST(ROUND(MAX( tb.lane_saturation_flow_rate * tb.flow_coefficient )) AS INT) saturation_flow_rate,
CAST(ROUND(SUM( tb.lane_capacity * tb.flow_coefficient )) AS INT) capacity,
CAST(ROUND(SUM( tb.lane_capacity * tb.flow_coefficient )/12) AS INT) capacity,
CAST(ROUND(SUM(traffic_flow_A * tb.flow_coefficient),0) AS INT) traffic_flow_A,
CAST(ROUND(SUM(traffic_flow_B * tb.flow_coefficient),0) AS INT) traffic_flow_B,
CAST(ROUND(SUM(traffic_flow_C * tb.flow_coefficient),0) AS INT) traffic_flow_C,
......@@ -723,13 +725,18 @@ create table t_analysis_cross_indicators
efficiency_index decimal(6,2),
evaluation_grade varchar,
service_level varchar,
traffic_flow_A INT,
traffic_flow_B INT,
traffic_flow_C INT,
PRIMARY KEY (cross_id,granularity,window_end_time) NOT ENFORCED
) WITH (
'connector' = 'jdbc',
'url' = 'jdbc:mysql://172.17.0.1:3306/holo_roadnet?characterEncoding=UTF-8&serverTimezone=Asia/Shanghai',
'table-name' = 't_analysis_cross_indicators',
'username' = 'root',
'password' = 'Wanji300552'
'password' = 'Wanji300552',
'sink.buffer-flush.max-rows' = '0',
'sink.buffer-flush.interval' = '1000'
);
-- 计算路口通过时长占比
......@@ -747,7 +754,7 @@ FROM (
GROUP BY tc.cross_id, tc.window_start, tc.window_end
;
insert into t_analysis_cross_indicators(cross_id,cross_name,speed,saturation,stop_num,max_queue_length,ruksj,granularity,avg_delay,capacity,flow,window_start_time,window_end_time,congest_index,no_stop_rate,once_stop_rate,second_stop_rate,three_stop_rate,green_start_max_queue,green_use_rate,hour_flow,efficiency_index,evaluation_grade,service_level)
insert into t_analysis_cross_indicators(cross_id,cross_name,speed,saturation,stop_num,max_queue_length,ruksj,granularity,avg_delay,capacity,flow,window_start_time,window_end_time,congest_index,no_stop_rate,once_stop_rate,second_stop_rate,three_stop_rate,green_start_max_queue,green_use_rate,hour_flow,efficiency_index,traffic_flow_A,traffic_flow_B,traffic_flow_C,evaluation_grade,service_level)
SELECT t.*,
-- 效率等级
(CASE WHEN t.efficiency_index>=7 THEN '1' WHEN t.efficiency_index>=3 THEN '2' ELSE '3' END) evaluation_grade,
......@@ -764,22 +771,27 @@ SELECT t.*,
FROM
(
SELECT t1.cross_id,t1.cross_name,t1.speed,t1.saturation,t1.stop_num,t1.max_queue_length,LOCALTIMESTAMP,t1.granularity,t1.avg_delay,t1.capacity,t1.flow,t1.start_window_time,t1.end_window_time,t1.congest_index,t1.no_stop_rate,t1.once_stop_rate,t1.second_stop_rate,t1.three_stop_rate,t1.green_start_max_queue,t1.green_use_rate,t1.hour_flow,
(
(t1.flow/t1.capacity) * 10 * 0.2 +
(t1.avg_lane_saturation) * 10 * 0.2 +
(t1.no_stop_rate + t1.once_stop_rate) * 10 * 0.3 +
(t2.free_travel_time / t2.travel_time) * 10 * 0.3
)/4 AS efficiency_index -- 效率指数
ifnull( (
(t1.flow/t1.capacity) * 10 * 0.2 +
(t1.avg_lane_saturation) * 10 * 0.2 +
(t1.no_stop_rate + t1.once_stop_rate) * 10 * 0.3 +
(ifnull(t2.free_travel_time,1) / ifnull(t2.travel_time,1)) * 10 * 0.3
),0) AS efficiency_index -- /4 AS efficiency_index -- 效率指数
,
t1.traffic_flow_A,
t1.traffic_flow_B,
t1.traffic_flow_C
FROM (
SELECT tb.cross_id,
tb.cross_name,
AVG(tb.mean_v) as speed,
SUM(tb.traffic_flow)/ SUM(tb.lane_capacity) saturation,
AVG(tb.lane_saturation) saturation,
-- SUM(tb.traffic_flow)*4/ (SUM(tb.lane_capacity)/12) saturation,
AVG(tb.mean_stops_number) stop_num,
CAST(ROUND(MAX(tb.queue_length),0) AS INT) max_queue_length,
'15m' granularity,
'1h' granularity,
AVG(tb.mean_delay) avg_delay,
SUM(tb.lane_capacity ) capacity,
CAST((SUM(tb.lane_capacity )/12) AS INT) capacity,
SUM(tb.traffic_flow) flow,
TUMBLE_START(tb.ts_ltz, INTERVAL '1' HOUR) start_window_time,
TUMBLE_END(tb.ts_ltz, INTERVAL '1' HOUR) end_window_time,
......@@ -791,10 +803,13 @@ FROM
CAST(MAX(tb.light_green_start_queue_length) AS INT) green_start_max_queue,
AVG( tb.green_light_efficiency) green_use_rate,
CAST(AVG(tb.lane_flow_rate) AS INT) hour_flow,
AVG(tb.lane_saturation) avg_lane_saturation
AVG(tb.lane_saturation) avg_lane_saturation,
SUM(tb.traffic_flow_A) traffic_flow_A,
SUM(tb.traffic_flow_B) traffic_flow_B,
SUM(tb.traffic_flow_C) traffic_flow_C
FROM v_kafka_cycle_data tb
group by TUMBLE(tb.ts_ltz, INTERVAL '1' HOUR),tb.cross_id,tb.cross_name
) t1
FULL JOIN v_pass_time_rate t2 on t1.cross_id=t2.cross_id and t1.start_window_time=t2.window_start and t1.end_window_time=t2.window_end
LEFT JOIN v_pass_time_rate t2 on t1.cross_id=t2.cross_id and t1.start_window_time=t2.window_start and t1.end_window_time=t2.window_end
) t
;
\ No newline at end of file
......@@ -42,12 +42,12 @@ CREATE TABLE source_gloabl_lane_cycle_data (
) WITH (
'connector' = 'kafka', -- 使用 kafka connector
'topic-pattern' = 'JN(.*)LanePeriodicData', -- kafka topic
'properties.bootstrap.servers' = '192.168.2.103:9092', -- broker连接信息
'properties.bootstrap.servers' = '37.12.182.31:9092', -- broker连接信息
'properties.group.id' = 't_global_lane_cycle_data_30m', -- 消费kafka的group_id
'properties.enable.auto.commit' = 'true',
'properties.auto.commit.interval.ms' = '1000',
'scan.startup.mode' = 'group-offsets',
-- 'scan.startup.mode' = 'latest-offset', -- 读取数据的位置
-- 'scan.startup.mode' = 'group-offsets',
'scan.startup.mode' = 'latest-offset', -- 读取数据的位置
-- 'scan.startup.mode' = 'earliest-offset',
-- 'scan.startup.mode' = 'group-offsets',
-- 'scan.startup.mode' = 'timestamp', -- 读取数据的位置
......@@ -271,7 +271,7 @@ SELECT tb.cross_id,
tb.lane_no,
tb.turn,
SUM(tb.traffic_flow),
SUM(tb.traffic_flow)/SUM(tb.lane_capacity) lane_saturation,
SUM(tb.traffic_flow)*4/(SUM(tb.lane_capacity)/6) lane_saturation,
AVG(tb.mean_delay),
AVG(tb.mean_v),
MAX(tb.queue_length),
......@@ -305,7 +305,7 @@ SELECT tb.cross_id,
AVG(tb.light_green_finish_queue_length),
AVG(tb.green_light_efficiency),
MAX(tb.lane_saturation_flow_rate),
SUM(tb.lane_capacity),
CAST((SUM(tb.lane_capacity )/6) AS INT) lane_capacity, -- 5分钟周期输出的通行能力的单位是辆/小时,30分钟累加求和以后按时间批次进行平均保持为小时单位,否则相当于6个小时通行能力
AVG(tb.lane_no_stop_rate),
AVG(tb.lane_three_stop_rate),
TUMBLE_START(tb.ts_ltz, INTERVAL '30' MINUTE) start_window_time,
......@@ -377,7 +377,9 @@ create table t_analysis_rid_entrace_indicator
'url' = 'jdbc:mysql://172.17.0.1:3306/holo_roadnet?characterEncoding=UTF-8&serverTimezone=Asia/Shanghai',
'table-name' = 't_analysis_rid_entrace_indicator',
'username' = 'root',
'password' = 'Wanji300552'
'password' = 'Wanji300552',
'sink.buffer-flush.max-rows' = '0',
'sink.buffer-flush.interval' = '1000'
);
-- 进口道指标
insert into t_analysis_rid_entrace_indicator(cross_id,cross_name,rid,rid_dir,traffic_index,capacity,flow,saturation,queue_length,speed,delay_time,stop_num,statistic_time,granularity,ruksj,window_start_time,window_end_time,
......@@ -389,7 +391,7 @@ SELECT tb1.cross_id,tb1.cross_name,tb1.rid,tb1.in_dir,
if(tb1.traffic_index>999,999,tb1.traffic_index),
tb1.lane_capacity,
tb1.traffic_flow,
(tb1.traffic_flow/tb1.lane_capacity) saturation,
(tb1.traffic_flow*4/tb1.lane_capacity) saturation,
tb1.queue_length,
tb1.mean_v,
tb1.mean_delay,
......@@ -435,7 +437,7 @@ SELECT tb1.cross_id,tb1.cross_name,tb1.rid,tb1.in_dir,
FROM (
SELECT tb.cross_id,tb.cross_name,tb.rid,tb.in_dir,
(ifnull(tb.free_speed,80)/avg(tb.mean_v)) as traffic_index,
SUM(tb.lane_capacity) lane_capacity,
CAST((SUM(tb.lane_capacity )/6) AS INT) lane_capacity, -- 5分钟周期输出的通行能力的单位是辆/小时,30分钟累加求和以后按时间批次进行平均保持为小时单位,否则相当于6个小时通行能力
SUM(tb.traffic_flow) traffic_flow,
AVG(tb.lane_saturation) lane_saturation,
MAX(tb.queue_length) queue_length,
......@@ -525,7 +527,9 @@ create table t_analysis_rid_turn_indicators
'url' = 'jdbc:mysql://172.17.0.1:3306/holo_roadnet?characterEncoding=UTF-8&serverTimezone=Asia/Shanghai',
'table-name' = 't_analysis_rid_turn_indicators',
'username' = 'root',
'password' = 'Wanji300552'
'password' = 'Wanji300552',
'sink.buffer-flush.max-rows' = '0',
'sink.buffer-flush.interval' = '1000'
);
create table t_config_lane_flow_coefficient
......@@ -670,7 +674,7 @@ FROM
AVG(light_green_start_queue_length ) light_green_start_queue_length,
AVG(light_green_finish_queue_length ) light_green_finish_queue_length,
CAST(ROUND(MAX( tb.lane_saturation_flow_rate * tb.flow_coefficient )) AS INT) saturation_flow_rate,
CAST(ROUND(SUM( tb.lane_capacity * tb.flow_coefficient )) AS INT) capacity,
CAST(ROUND(SUM( tb.lane_capacity * tb.flow_coefficient )/6) AS INT) capacity,
CAST(ROUND(SUM(traffic_flow_A * tb.flow_coefficient),0) AS INT) traffic_flow_A,
CAST(ROUND(SUM(traffic_flow_B * tb.flow_coefficient),0) AS INT) traffic_flow_B,
CAST(ROUND(SUM(traffic_flow_C * tb.flow_coefficient),0) AS INT) traffic_flow_C,
......@@ -722,13 +726,18 @@ create table t_analysis_cross_indicators
efficiency_index decimal(6,2),
evaluation_grade varchar,
service_level varchar,
traffic_flow_A INT,
traffic_flow_B INT,
traffic_flow_C INT,
PRIMARY KEY (cross_id,granularity,window_end_time) NOT ENFORCED
) WITH (
'connector' = 'jdbc',
'url' = 'jdbc:mysql://172.17.0.1:3306/holo_roadnet?characterEncoding=UTF-8&serverTimezone=Asia/Shanghai',
'table-name' = 't_analysis_cross_indicators',
'username' = 'root',
'password' = 'Wanji300552'
'password' = 'Wanji300552',
'sink.buffer-flush.max-rows' = '0',
'sink.buffer-flush.interval' = '1000'
);
-- 计算路口通过时长占比
......@@ -746,7 +755,7 @@ FROM (
GROUP BY tc.cross_id, tc.window_start, tc.window_end
;
insert into t_analysis_cross_indicators(cross_id,cross_name,speed,saturation,stop_num,max_queue_length,ruksj,granularity,avg_delay,capacity,flow,window_start_time,window_end_time,congest_index,no_stop_rate,once_stop_rate,second_stop_rate,three_stop_rate,green_start_max_queue,green_use_rate,hour_flow,efficiency_index,evaluation_grade,service_level)
insert into t_analysis_cross_indicators(cross_id,cross_name,speed,saturation,stop_num,max_queue_length,ruksj,granularity,avg_delay,capacity,flow,window_start_time,window_end_time,congest_index,no_stop_rate,once_stop_rate,second_stop_rate,three_stop_rate,green_start_max_queue,green_use_rate,hour_flow,efficiency_index,traffic_flow_A,traffic_flow_B,traffic_flow_C,evaluation_grade,service_level)
SELECT t.*,
-- 效率等级
(CASE WHEN t.efficiency_index>=7 THEN '1' WHEN t.efficiency_index>=3 THEN '2' ELSE '3' END) evaluation_grade,
......@@ -763,22 +772,27 @@ SELECT t.*,
FROM
(
SELECT t1.cross_id,t1.cross_name,t1.speed,t1.saturation,t1.stop_num,t1.max_queue_length,LOCALTIMESTAMP ruksj,t1.granularity,t1.avg_delay,t1.capacity,t1.flow,t1.start_window_time,t1.end_window_time,t1.congest_index,t1.no_stop_rate,t1.once_stop_rate,t1.second_stop_rate,t1.three_stop_rate,t1.green_start_max_queue,t1.green_use_rate,t1.hour_flow,
(
(t1.flow/t1.capacity) * 10 * 0.2 +
(t1.avg_lane_saturation) * 10 * 0.2 +
(t1.no_stop_rate + t1.once_stop_rate) * 10 * 0.3 +
(t2.free_travel_time / t2.travel_time) * 10 * 0.3
)/4 AS efficiency_index -- 效率指数
ifnull((
(t1.flow/t1.capacity) * 10 * 0.2 +
(t1.avg_lane_saturation) * 10 * 0.2 +
(t1.no_stop_rate + t1.once_stop_rate) * 10 * 0.3 +
(ifnull(t2.free_travel_time,1) / ifnull(t2.travel_time,1)) * 10 * 0.3
),0) AS efficiency_index -- /4 AS efficiency_index -- 效率指数
,
t1.traffic_flow_A,
t1.traffic_flow_B,
t1.traffic_flow_C
FROM (
SELECT tb.cross_id,
tb.cross_name,
AVG(tb.mean_v) as speed,
SUM(tb.traffic_flow)/ SUM(tb.lane_capacity) saturation,
-- SUM(tb.traffic_flow)*4/ (SUM(tb.lane_capacity)/6) saturation,
AVG(tb.lane_saturation) saturation,
AVG(tb.mean_stops_number) stop_num,
CAST(ROUND(MAX(tb.queue_length),0) AS INT) max_queue_length,
'30m' granularity,
AVG(tb.mean_delay) avg_delay,
SUM(tb.lane_capacity ) capacity,
CAST((SUM(tb.lane_capacity )/6) AS INT) capacity, -- 5分钟周期输出的通行能力的单位是辆/小时,30分钟累加求和以后按时间批次进行平均保持为小时单位,否则相当于6个小时通行能力
SUM(tb.traffic_flow) flow,
TUMBLE_START(tb.ts_ltz, INTERVAL '30' MINUTE) start_window_time,
TUMBLE_END(tb.ts_ltz, INTERVAL '30' MINUTE) end_window_time,
......@@ -790,10 +804,13 @@ FROM
CAST(MAX(tb.light_green_start_queue_length) AS INT) green_start_max_queue,
AVG( tb.green_light_efficiency) green_use_rate,
CAST(AVG(tb.lane_flow_rate) AS INT) hour_flow,
AVG(tb.lane_saturation) avg_lane_saturation
AVG(tb.lane_saturation) avg_lane_saturation,
SUM(tb.traffic_flow_A) traffic_flow_A,
SUM(tb.traffic_flow_B) traffic_flow_B,
SUM(tb.traffic_flow_C) traffic_flow_C
FROM v_kafka_cycle_data tb
group by TUMBLE(tb.ts_ltz, INTERVAL '30' MINUTE),tb.cross_id,tb.cross_name
) t1
FULL JOIN v_pass_time_rate t2 on t1.cross_id=t2.cross_id and t1.start_window_time=t2.window_start and t1.end_window_time=t2.window_end
LEFT JOIN v_pass_time_rate t2 on t1.cross_id=t2.cross_id and t1.start_window_time=t2.window_start and t1.end_window_time=t2.window_end
) t
;
\ No newline at end of file
......@@ -40,7 +40,7 @@ CREATE TABLE source_gloabl_lane_cycle_data (
) WITH (
'connector' = 'kafka', -- 使用 kafka connector
'topic-pattern' = 'JN(.*)LanePeriodicData', -- kafka topic
'properties.bootstrap.servers' = '192.168.2.103:9092', -- broker连接信息
'properties.bootstrap.servers' = '37.12.182.31:9092', -- broker连接信息
'properties.group.id' = 't_global_lane_cycle_data_5m', -- 消费kafka的group_id
'properties.enable.auto.commit' = 'true',
'properties.auto.commit.interval.ms' = '1000',
......@@ -111,6 +111,7 @@ create table t_analysis_rid_lane_indicators
'password' = 'Wanji300552',
'sink.buffer-flush.max-rows' = '0',
'sink.buffer-flush.interval' = '1000'
,'sink.parallelism' = '2'
);
create table t_base_lane_info (
cross_id VARCHAR, -- 路口ID
......@@ -355,7 +356,10 @@ create table t_analysis_rid_entrace_indicator
'url' = 'jdbc:mysql://172.17.0.1:3306/holo_roadnet?characterEncoding=UTF-8&serverTimezone=Asia/Shanghai',
'table-name' = 't_analysis_rid_entrace_indicator',
'username' = 'root',
'password' = 'Wanji300552'
'password' = 'Wanji300552',
'sink.buffer-flush.max-rows' = '0',
'sink.buffer-flush.interval' = '1000'
,'sink.parallelism' = '2'
);
-- 进口道指标
-- 进口道指标
......@@ -380,7 +384,7 @@ SELECT tb1.cross_id,tb1.cross_name,tb1.rid,tb1.in_dir,
) traffic_state,
tb1.lane_capacity,
tb1.traffic_flow,
(tb1.traffic_flow/tb1.lane_capacity) saturation,
((tb1.traffic_flow * 12)/tb1.lane_capacity) saturation,
tb1.queue_length,
tb1.mean_v,
tb1.mean_delay,
......@@ -415,7 +419,7 @@ SELECT tb1.cross_id,tb1.cross_name,tb1.rid,tb1.in_dir,
FROM (
SELECT tb.cross_id,tb.cross_name,tb.rid,tb.in_dir,
(ifnull(tb.free_speed,80)/avg(tb.mean_v)) as traffic_index,
MAX(tb.lane_capacity) lane_capacity,
SUM(tb.lane_capacity) lane_capacity,
SUM(tb.traffic_flow) traffic_flow,
AVG(tb.lane_saturation) lane_saturation,
MAX(tb.queue_length) queue_length,
......@@ -505,7 +509,10 @@ create table t_analysis_rid_turn_indicators
'url' = 'jdbc:mysql://172.17.0.1:3306/holo_roadnet?characterEncoding=UTF-8&serverTimezone=Asia/Shanghai',
'table-name' = 't_analysis_rid_turn_indicators',
'username' = 'root',
'password' = 'Wanji300552'
'password' = 'Wanji300552',
'sink.buffer-flush.max-rows' = '0',
'sink.buffer-flush.interval' = '1000'
,'sink.parallelism' = '2'
);
create table t_config_lane_flow_coefficient
......@@ -650,7 +657,7 @@ FROM
AVG(light_green_start_queue_length ) light_green_start_queue_length,
AVG(light_green_finish_queue_length ) light_green_finish_queue_length,
CAST(ROUND(MAX( tb.lane_saturation_flow_rate * tb.flow_coefficient )) AS INT) saturation_flow_rate,
CAST(ROUND(MAX( tb.lane_capacity * tb.flow_coefficient )) AS INT) capacity,
CAST(ROUND(SUM( tb.lane_capacity * tb.flow_coefficient )) AS INT) capacity,
CAST(ROUND(SUM(traffic_flow_A * tb.flow_coefficient),0) AS INT) traffic_flow_A,
CAST(ROUND(SUM(traffic_flow_B * tb.flow_coefficient),0) AS INT) traffic_flow_B,
CAST(ROUND(SUM(traffic_flow_C * tb.flow_coefficient),0) AS INT) traffic_flow_C,
......@@ -704,32 +711,25 @@ create table t_analysis_cross_indicators
efficiency_index decimal(6,2),
evaluation_grade varchar,
service_level varchar,
traffic_flow_A INT,
traffic_flow_B INT,
traffic_flow_C INT,
PRIMARY KEY (cross_id,granularity,window_end_time) NOT ENFORCED
) WITH (
'connector' = 'jdbc',
'url' = 'jdbc:mysql://172.17.0.1:3306/holo_roadnet?characterEncoding=UTF-8&serverTimezone=Asia/Shanghai',
'table-name' = 't_analysis_cross_indicators',
'username' = 'root',
'password' = 'Wanji300552'
'password' = 'Wanji300552',
'sink.buffer-flush.max-rows' = '0',
'sink.buffer-flush.interval' = '1000'
,'sink.parallelism' = '2'
);
-- 计算路口通过时长占比
CREATE VIEW v_pass_time_rate AS
SELECT tc.cross_id, SUM(tc.free_travel_time) free_travel_time,SUM(tc.travel_time) as travel_time
FROM (
SELECT tb.cross_id,
tb.rid,
(tb.ridLength / tb.free_speed) free_travel_time,
(tb.ridLength / if(avg(tb.mean_v)=0,1,avg(tb.mean_v))) travel_time
FROM v_kafka_cycle_data tb
GROUP BY tb.cross_id, tb.cross_name, tb.rid, tb.ridLength, tb.free_speed
) tc
GROUP BY tc.cross_id
;
insert into t_analysis_cross_indicators(cross_id,cross_name,speed,saturation,stop_num,max_queue_length,ruksj,granularity,avg_delay,capacity,flow,window_start_time,window_end_time,congest_index,no_stop_rate,once_stop_rate,second_stop_rate,three_stop_rate,green_start_max_queue,green_use_rate,hour_flow,efficiency_index,evaluation_grade,service_level)
SELECT t.*,(CASE WHEN t.efficiency_index>=7 THEN '1' WHEN t.efficiency_index>=3 THEN '2' ELSE '3' END) evaluation_grade,
insert into t_analysis_cross_indicators(cross_id,cross_name,speed,saturation,stop_num,max_queue_length,ruksj,granularity,avg_delay,capacity,flow,window_start_time,window_end_time,congest_index,no_stop_rate,once_stop_rate,second_stop_rate,three_stop_rate,green_start_max_queue,green_use_rate,hour_flow,efficiency_index,traffic_flow_A,traffic_flow_B,traffic_flow_C,evaluation_grade,service_level)
SELECT t.*,
'0' as evaluation_grade,
(CASE WHEN t.saturation<0.4 THEN 'A'
WHEN t.saturation>=0.4 and t.saturation<0.6 THEN 'B'
WHEN t.saturation>=0.6 and t.saturation<0.75 THEN 'C'
......@@ -742,7 +742,8 @@ FROM(
SELECT tb.cross_id,
tb.cross_name,
AVG(tb.mean_v),
(SUM(tb.traffic_flow) / SUM(tb.lane_capacity)) saturation ,
-- (SUM(tb.traffic_flow)*12 / SUM(tb.lane_capacity)) saturation ,
AVG(tb.lane_saturation) saturation,
AVG(tb.mean_stops_number),
CAST(ROUND(MAX(tb.queue_length),0) AS INT),
LOCALTIMESTAMP,
......@@ -760,14 +761,12 @@ FROM(
CAST(MAX(tb.light_green_start_queue_length) AS INT),
AVG( tb.green_light_efficiency),
CAST(AVG(tb.lane_flow_rate) AS INT) hour_flow,
( (SUM(tb.traffic_flow) / SUM(tb.lane_capacity) * 10 * 0.2 +
AVG(tb.lane_saturation) * 10 * 0.2 +
(AVG( tb.lane_no_stop_rate )+AVG( tb.lane_one_stop_rate ))*10*0.3 +
(avg(tc.free_travel_time)/avg(tc.travel_time)) * 10 * 0.3
)/4
) efficiency_index
0 as efficiency_index, -- 临时
SUM(tb.traffic_flow_A) traffic_flow_A,
SUM(tb.traffic_flow_B) traffic_flow_B,
SUM(tb.traffic_flow_C) traffic_flow_C
FROM v_kafka_cycle_data tb
JOIN v_pass_time_rate tc on tb.cross_id=tc.cross_id
-- LEFT JOIN v_pass_time_rate tc on tb.cross_id=tc.cross_id
group by tb.cross_id,tb.cross_name,tb.start_window_time,tb.end_window_time
) t
;
\ No newline at end of file
;
-- Flink CDC 参考:https://blog.csdn.net/qq_44326412/article/details/127064981
SET 'execution.checkpointing.interval' = '30s';
......
package com.wanji.indicators.task.conflictpoint;
import com.wanji.indicators.model.BaseEventResultModel;
import com.wanji.indicators.model.ConflictPointModelBase;
import com.wanji.indicators.model.EventCross;
import com.wanji.indicators.model.FrameModel;
import com.wanji.indicators.source.WaitingAreaSource;
import com.wanji.indicators.task.conflictpoint.func.*;
import com.wanji.indicators.util.PropertiesHelper;
import com.wanji.indicators.util.PtInPolyUtil;//PtInPolyUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.flink.api.common.functions.FlatMapFunction;
import org.apache.flink.streaming.api.datastream.DataStream;
import org.apache.flink.streaming.api.datastream.SingleOutputStreamOperator;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.util.Collector;
import java.io.Serializable;
import java.util.Properties;
public class ConflictEventMainTest implements Serializable {
private StreamExecutionEnvironment env;
private PropertiesHelper instance;
private Properties p;
private String path;
private ConflictEventMainTest(StreamExecutionEnvironment env, String path) {
this.env = env;
this.instance = PropertiesHelper.getInstance();
this.p = instance.getProperties();
this.path = path;
}
public static ConflictEventMainTest init(StreamExecutionEnvironment env, String path) {
return new ConflictEventMainTest(env, path);
}
public void run(DataStream<FrameModel> streamSource) {
/**
* 转换数据为实体类 并筛选需要计算的数据(路口面 上的数据)
*/
SingleOutputStreamOperator<FrameModel> eventStream = streamSource
.flatMap(new ConflictFrameFlatMap())
.setParallelism(1)
.name("冲突点-解析数据");
/**
* 读取路口待转区配置 并过滤待转区
*/
SingleOutputStreamOperator<FrameModel> flatMapWaitingArea = eventStream
.connect(env.addSource(new WaitingAreaSource()).name("冲突点-查询路口待转区配置").broadcast())
.flatMap(new ConflictWaitingAreaCoFlatMap())
.setParallelism(1)
.name("冲突点-匹配待转区并过滤其数据");
/**
* 过滤拥堵状态下的冲突点数据
*/
SingleOutputStreamOperator<FrameModel> frameModelOutputStream = flatMapWaitingArea
.flatMap(new ConflictCongestionFilterFlatMap())
.setParallelism(1)
.name("冲突点-过滤拥堵状态下的停驶车辆数据");
/**
* 按照 crossId + time 分组
*/
SingleOutputStreamOperator<EventCross> processWindowStopAndRuning = frameModelOutputStream
.flatMap(new ConflictCheckConflictFlatMap())
.setParallelism(1)
.name("冲突点-计算是否发生冲突");
/**
* 去重
*/
SingleOutputStreamOperator<EventCross> eventMapState = processWindowStopAndRuning
.keyBy("crossId","trackID")
.process(new ConflictDeduplicationKeyedProcess())
.setParallelism(1)
.name("冲突点-结果去重");
/**
* 构建结果集
*/
SingleOutputStreamOperator<BaseEventResultModel> eventTestSingleOutput = eventMapState
.flatMap(new FlatMapFunction<EventCross, BaseEventResultModel>() {
@Override
public void flatMap(EventCross event, Collector<BaseEventResultModel> collector) throws Exception {
if (StringUtils.isNotBlank(event.getPlateNumber())) {
ConflictPointModelBase model = new ConflictPointModelBase();
model.setCrossId(event.getCrossId());
model.setTrackId(event.getTrackID());
model.setPlateNumber(event.getPlateNumber());
model.setVehicleBrand(event.getVehicleBrand());
model.setPlateColor(event.getPlateColor());
model.setPlateType(event.getPlateType());
model.setVehicleType(event.getVehicleType() + "");
model.setTrackIdNear(event.getTrackIdNear());
// model.setEventClass(EventType.EVENT.getName());
// model.setEventType(EventType.CONFLICT_POINT.getName());
// model.setTypeCode(EventType.CONFLICT_POINT.getCode());
model.setDesc("路口面冲突点: 车辆 " + event.getPlateNumber() + "行驶方向为 " + PtInPolyUtil.getDir(event.getDriveAngle()));
String matchLane = event.getMatchLane();
String entryLane = event.getEntryLane();
if (StringUtils.isNotBlank(matchLane)) {
model.setLaneId(matchLane);
model.setRid(matchLane.substring(0, 23));
} else {
if (StringUtils.isNotBlank(entryLane)) {
model.setLaneId(entryLane);
model.setRid(entryLane.substring(0, 23));
}
}
model.setStartTime(event.getTime() - 1000L);
model.setEndTime(event.getTime() + 1000L);
model.setX(event.getLng());
model.setY(event.getLat());
model.setDuration(2000);
model.setTime(model.getStartTime());
if (model.getEndTime() > 0 &&
model.getStartTime() > 0 &&
model.getEndTime() > model.getStartTime()) {
collector.collect(model);
}
}
}
})
.setParallelism(1);
// eventTestSingleOutput.addSink(new EventFileSink(this.path));
}
}
......@@ -57,7 +57,7 @@ public class TrackExportToFileMain {
if (!sinkPath.endsWith("/")) {
sinkPath += "/";
}
sinkPath += startTime + "-" + endTime + ".json";
sinkPath += topic+"_"+startTime + "-" + endTime + ".json";
log.info("导出路径:" + sinkPath);
long startTimestamp = DateUtil.StringToMillis(startTime, "yyyyMMddHHmmss");
......@@ -180,7 +180,7 @@ public class TrackExportToFileMain {
toJsonStream.addSink(new FileSink(sinkPath));
env.execute("根据起始时间范围导出数据到文件");
env.executeAsync().cancel();
//env.executeAsync().cancel();
} catch (Exception e) {
e.printStackTrace();
//log.error("交通指标计算任务异常 : " + e);
......
......@@ -86,7 +86,7 @@ public class FreeFlowSpeedMain {
flatMap(new FlatMapFunction<FrameModel, FrameMaxSpeedModel>() {
@Override
public void flatMap(FrameModel value, Collector<FrameMaxSpeedModel> out) throws Exception {
List<CarTrackModel> list = value.getE1FrameParticipant();
List<CarTrackModel> list = value.getTrackList();
String motorObjectType = Constant.MOTOR_TYPES;
String[] sps = motorObjectType.split(",");
......
......@@ -39,39 +39,16 @@ public class CarTrackFlatMap implements FlatMapFunction<FrameModel, CarTrackMode
Integer participantNum = frameModel.getParticipantNum();
String globalId = frameModel.getOrgCode();
List<CarTrackModel> list = frameModel.getE1FrameParticipant();
List<CarTrackModel> list = frameModel.getTrackList();
String[] sps = motorObjectType.split(",");
List<String> motorTypeList = Arrays.asList(sps);
list.forEach(o->{
String type = o.getOriginalType().toString();
/*****************模拟车牌号、车辆颜色、车牌颜色******************************/
if (isMockPlate) {
if (motorTypeList.contains(type)) {
Integer id = o.getId();
String[] mockData = randomCarNumMap.get(id);
if (Objects.isNull(mockData)) {
String carNum = CarNumGenerator.getCarNum();
Integer picColor = getRandom(0, 7);
Integer bodyColor = getRandom(1, 9);
Integer function = getRandom(1, 5);
Integer ownership = getRandom(1, 5);
mockData = new String[]{carNum, picColor.toString(), bodyColor.toString(), function.toString(), ownership.toString()};
randomCarNumMap.put(id, mockData);
}
o.setPicLicense(mockData[0]);
o.setLicenseColor(Integer.valueOf(mockData[1]));
o.setOriginalColor(Integer.valueOf(mockData[2]));
o.setFunction(Integer.valueOf(mockData[3]));
o.setOwnership(Integer.valueOf(mockData[4]));
}
}
/***********************************************/
o.setTimeStamp(DateUtil.toDateTime(globalTimeStamp,"yyyy-MM-dd HH:mm:ss.SSS"));
o.setGlobalTimeStamp(globalTimeStamp);
o.setOrgCode(globalId);
collector.collect(o);
});
}
......
......@@ -89,7 +89,7 @@ public class ProcessCarTrackByKey extends ProcessWindowFunction<CarTrackModel
}
singleCarTrackListModel.setTracks(trackList);
singleCarTrackListModel.setRoadnets(roadNets);
singleCarTrackListModel.setRoadNets(roadNets);
// log.info("plateNo:{},startTime:{},endTime:{},size:{}",singleCarTrackListModel.getStaticProperty().getPicLicense(),singleCarTrackListModel.getStaticProperty().getStartTime(),singleCarTrackListModel.getStaticProperty().getEndTime(),trackList.size());
out.collect(singleCarTrackListModel);
}
......
package com.wanji.indicators.udf;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.wanji.indicators.model.CarTrackModel;
import com.wanji.indicators.source.ConflictTurnSource;
import org.apache.flink.api.common.typeinfo.TypeInformation;
import org.apache.flink.api.common.typeinfo.Types;
import org.apache.flink.table.annotation.DataTypeHint;
import org.apache.flink.table.annotation.FunctionHint;
import org.apache.flink.table.functions.TableFunction;
import org.apache.flink.types.Row;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.Type;
import java.util.Iterator;
import java.util.List;
/**
* @author fengyi
* @date 2023/9/21
* @description
*/
@FunctionHint(output = @DataTypeHint("ROW<id INT, picLicense STRING, originalType INT, speed DOUBLE,crossId STRING,rid STRING,laneId STRING>"))
public class ParserJsonArray extends TableFunction<Row> {
private static final Logger log = LoggerFactory.getLogger(ParserJsonArray.class);
public void eval(String value) {
try {
long s = System.currentTimeMillis();
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
List<CarTrackModel> list = objectMapper.readValue(value, new TypeReference<List<CarTrackModel>>() {
@Override
public Type getType() {
return super.getType();
}
});
for (CarTrackModel carTrackModel : list) {
Integer id = carTrackModel.getId();
String picLicense = carTrackModel.getPicLicense();
Integer originalType = carTrackModel.getOriginalType();
Double speed = carTrackModel.getSpeed();
CarTrackModel.RoadNet roadNet = carTrackModel.getRoadnet();;
String crossId = roadNet.getCrossId();
String rid = roadNet.getRid();
String laneId = roadNet.getLaneId();
}
long e = System.currentTimeMillis();
System.out.println("耗时:"+(e-s)+"ms");
JSONArray arrays = JSONArray.parseArray(value);
Iterator<Object> iterator = arrays.iterator();
while (iterator.hasNext()) {
JSONObject jsonObject = (JSONObject) iterator.next();
Integer id = jsonObject.getIntValue("id") ;
String picLicense = jsonObject.getString("picLicense");
Integer originalType = jsonObject.getIntValue("originalType") ;
Double speed = jsonObject.getDoubleValue("speed") ;
JSONObject roadnet = jsonObject.getJSONObject("roadnet");
String crossId = roadnet.getString("crossId");
String rid = roadnet.getString("rid");
String laneId = roadnet.getString("laneId");
//collect(Row.of(id,picLicense,originalType,speed,crossId,rid,laneId));
}
long e1 = System.currentTimeMillis();
System.out.println("耗时:"+(e1-e)+"ms");
} catch (Exception e) {
log.error("Parser json failed :" + e.getMessage());
}
}
public static void main(String[] args) {
String json = "[{\"id\":692652,\"licenseColor\":0,\"picLicense\":\"鲁A35ER0\",\"originalColor\":0,\"originalType\":1,\"longitude\":117.08762759999999,\"latitude\":36.642938199999996,\"speed\":56.24,\"altitude\":0.0,\"courseAngle\":55.0,\"baseLocation\":0,\"waitingTime\":0,\"stopNum\":0,\"roadnet\":{\"crossId\":\"null\",\"laneId\":\"13NF80B5QN013NGH0B5RC0024012\",\"rid\":\"13NF80B5QN013NGH0B5RC00\",\"segmentId\":\"13NF80B5QN013NGH0B5RC00240\"}},{\"id\":692630,\"licenseColor\":9,\"picLicense\":null,\"originalColor\":0,\"originalType\":1,\"longitude\":117.0961889,\"latitude\":36.644816999999996,\"speed\":1.8,\"altitude\":0.0,\"courseAngle\":314.0,\"baseLocation\":0,\"waitingTime\":23,\"stopNum\":9,\"roadnet\":{\"crossId\":\"13NHC0B5R40\",\"laneId\":\"13NHC0B5R4013NID0B5RM0090013\",\"rid\":\"13NHC0B5R4013NID0B5RM00\",\"segmentId\":\"13NHC0B5R4013NID0B5RM00900\"}},{\"id\":692631,\"licenseColor\":9,\"picLicense\":null,\"originalColor\":0,\"originalType\":1,\"longitude\":117.09669939999999,\"latitude\":36.644965299999996,\"speed\":2.13,\"altitude\":0.0,\"courseAngle\":272.0,\"baseLocation\":0,\"waitingTime\":25,\"stopNum\":1,\"roadnet\":{\"crossId\":\"null\",\"laneId\":\"13NH20B5RH013NID0B5RM0020011\",\"rid\":\"13NH20B5RH013NID0B5RM00\",\"segmentId\":\"13NH20B5RH013NID0B5RM00200\"}},{\"id\":692632,\"licenseColor\":9,\"picLicense\":null,\"originalColor\":0,\"originalType\":1,\"longitude\":117.0918439,\"latitude\":36.6446373,\"speed\":44.93,\"altitude\":0.0,\"courseAngle\":254.0,\"baseLocation\":0,\"waitingTime\":0,\"stopNum\":0,\"roadnet\":{\"crossId\":\"null\",\"laneId\":\"13NI00B5RM013NGH0B5RC0024013\",\"rid\":\"13NI00B5RM013NGH0B5RC00\",\"segmentId\":\"13NI00B5RM013NGH0B5RC00240\"}},{\"id\":692639,\"licenseColor\":0,\"picLicense\":\"鲁A39S5M\",\"originalColor\":6,\"originalType\":1,\"longitude\":117.0874949,\"latitude\":36.642977099999996,\"speed\":45.94,\"altitude\":0.0,\"courseAngle\":235.0,\"baseLocation\":0,\"waitingTime\":0,\"stopNum\":0,\"roadnet\":{\"crossId\":\"null\",\"laneId\":\"13NGH0B5RC013NF80B5QN0026012\",\"rid\":\"13NGH0B5RC013NF80B5QN00\",\"segmentId\":\"13NGH0B5RC013NF80B5QN00260\"}},{\"id\":692645,\"licenseColor\":0,\"picLicense\":\"鲁A3CU96\",\"originalColor\":0,\"originalType\":1,\"longitude\":117.0878695,\"latitude\":36.643127799999995,\"speed\":41.04,\"altitude\":0.0,\"courseAngle\":240.0,\"baseLocation\":0,\"waitingTime\":0,\"stopNum\":0,\"roadnet\":{\"crossId\":\"null\",\"laneId\":\"13NGH0B5RC013NF80B5QN0024011\",\"rid\":\"13NGH0B5RC013NF80B5QN00\",\"segmentId\":\"13NGH0B5RC013NF80B5QN00240\"}},{\"id\":692646,\"licenseColor\":9,\"picLicense\":null,\"originalColor\":0,\"originalType\":1,\"longitude\":117.09524239999999,\"latitude\":36.644929999999995,\"speed\":37.23,\"altitude\":0.0,\"courseAngle\":87.0,\"baseLocation\":0,\"waitingTime\":20,\"stopNum\":1,\"roadnet\":{\"crossId\":\"null\",\"laneId\":\"13NI00B5RM013NID0B5RM0010012\",\"rid\":\"13NI00B5RM013NID0B5RM00\",\"segmentId\":\"13NI00B5RM013NID0B5RM00100\"}},{\"id\":692648,\"licenseColor\":9,\"picLicense\":null,\"originalColor\":0,\"originalType\":1,\"longitude\":117.0966249,\"latitude\":36.644986599999996,\"speed\":3.93,\"altitude\":0.0,\"courseAngle\":272.0,\"baseLocation\":0,\"waitingTime\":20,\"stopNum\":1,\"roadnet\":{\"crossId\":\"null\",\"laneId\":\"13NH20B5RH013NID0B5RM0020012\",\"rid\":\"13NH20B5RH013NID0B5RM00\",\"segmentId\":\"13NH20B5RH013NID0B5RM00200\"}},{\"id\":692651,\"licenseColor\":0,\"picLicense\":\"鲁A6G0B2\",\"originalColor\":1,\"originalType\":1,\"longitude\":117.08633619999999,\"latitude\":36.642184,\"speed\":35.57,\"altitude\":0.0,\"courseAngle\":50.0,\"baseLocation\":0,\"waitingTime\":0,\"stopNum\":0,\"roadnet\":{\"crossId\":\"null\",\"laneId\":\"13NF80B5QN013NGH0B5RC0010011\",\"rid\":\"13NF80B5QN013NGH0B5RC00\",\"segmentId\":\"13NF80B5QN013NGH0B5RC00100\"}},{\"id\":692629,\"licenseColor\":9,\"picLicense\":null,\"originalColor\":0,\"originalType\":1,\"longitude\":117.0964281,\"latitude\":36.645001,\"speed\":12.42,\"altitude\":0.0,\"courseAngle\":272.0,\"baseLocation\":0,\"waitingTime\":21,\"stopNum\":1,\"roadnet\":{\"crossId\":\"13NHC0B5R40\",\"laneId\":\"13NH20B5RH013NID0B5RM0020012\",\"rid\":\"13NH20B5RH013NID0B5RM00\",\"segmentId\":\"13NH20B5RH013NID0B5RM00200\"}},{\"id\":692654,\"licenseColor\":9,\"picLicense\":null,\"originalColor\":0,\"originalType\":6,\"longitude\":117.08942789999999,\"latitude\":36.6439154,\"speed\":19.62,\"altitude\":0.0,\"courseAngle\":252.0,\"baseLocation\":0,\"waitingTime\":18,\"stopNum\":1,\"roadnet\":{\"crossId\":\"13NGH0B5RC0\",\"laneId\":\"13NGH0B5RC013NF80B5QN0010013\",\"rid\":\"13NGH0B5RC013NF80B5QN00\",\"segmentId\":\"13NGH0B5RC013NF80B5QN00100\"}},{\"id\":692655,\"licenseColor\":0,\"picLicense\":\"默A00000\",\"originalColor\":0,\"originalType\":6,\"longitude\":117.0868454,\"latitude\":36.6424421,\"speed\":45.0,\"altitude\":0.0,\"courseAngle\":51.0,\"baseLocation\":0,\"waitingTime\":0,\"stopNum\":0,\"roadnet\":{\"crossId\":\"null\",\"laneId\":\"13NF80B5QN013NGH0B5RC0020013\",\"rid\":\"13NF80B5QN013NGH0B5RC00\",\"segmentId\":\"13NF80B5QN013NGH0B5RC00200\"}},{\"id\":692657,\"licenseColor\":9,\"picLicense\":null,\"originalColor\":0,\"originalType\":1,\"longitude\":117.0961619,\"latitude\":36.6447788,\"speed\":2.24,\"altitude\":0.0,\"courseAngle\":314.0,\"baseLocation\":0,\"waitingTime\":11,\"stopNum\":1,\"roadnet\":{\"crossId\":\"13NHC0B5R40\",\"laneId\":\"13NHC0B5R4013NID0B5RM0090011\",\"rid\":\"13NHC0B5R4013NID0B5RM00\",\"segmentId\":\"13NHC0B5R4013NID0B5RM00900\"}},{\"id\":692658,\"licenseColor\":0,\"picLicense\":\"鲁A318WN\",\"originalColor\":0,\"originalType\":1,\"longitude\":117.087513,\"latitude\":36.6428933,\"speed\":53.39,\"altitude\":0.0,\"courseAngle\":55.0,\"baseLocation\":0,\"waitingTime\":0,\"stopNum\":0,\"roadnet\":{\"crossId\":\"null\",\"laneId\":\"13NF80B5QN013NGH0B5RC0024012\",\"rid\":\"13NF80B5QN013NGH0B5RC00\",\"segmentId\":\"13NF80B5QN013NGH0B5RC00240\"}},{\"id\":692660,\"licenseColor\":9,\"picLicense\":null,\"originalColor\":0,\"originalType\":1,\"longitude\":117.0853286,\"latitude\":36.6416263,\"speed\":21.68,\"altitude\":0.0,\"courseAngle\":231.0,\"baseLocation\":0,\"waitingTime\":0,\"stopNum\":0,\"roadnet\":{\"crossId\":\"null\",\"laneId\":\"13NF80B5QN013NED0B5Q90010013\",\"rid\":\"13NF80B5QN013NED0B5Q900\",\"segmentId\":\"13NF80B5QN013NED0B5Q900100\"}},{\"id\":692664,\"licenseColor\":9,\"picLicense\":null,\"originalColor\":0,\"originalType\":1,\"longitude\":117.09598559999999,\"latitude\":36.645036999999995,\"speed\":27.33,\"altitude\":0.0,\"courseAngle\":271.0,\"baseLocation\":0,\"waitingTime\":10,\"stopNum\":1,\"roadnet\":{\"crossId\":\"13NHC0B5R40\",\"laneId\":\"null\",\"rid\":\"null\",\"segmentId\":\"null\"}},{\"id\":692665,\"licenseColor\":0,\"picLicense\":\"鲁A6N0S6\",\"originalColor\":1,\"originalType\":1,\"longitude\":117.09002149999999,\"latitude\":36.6438693,\"speed\":6.38,\"altitude\":0.0,\"courseAngle\":338.0,\"baseLocation\":0,\"waitingTime\":0,\"stopNum\":0,\"roadnet\":{\"crossId\":\"13NGH0B5RC0\",\"laneId\":\"null\",\"rid\":\"null\",\"segmentId\":\"null\"}},{\"id\":692604,\"licenseColor\":9,\"picLicense\":null,\"originalColor\":0,\"originalType\":1,\"longitude\":117.0955094,\"latitude\":36.644930699999996,\"speed\":47.45,\"altitude\":0.0,\"courseAngle\":89.0,\"baseLocation\":0,\"waitingTime\":31,\"stopNum\":1,\"roadnet\":{\"crossId\":\"null\",\"laneId\":\"13NI00B5RM013NID0B5RM0090012\",\"rid\":\"13NI00B5RM013NID0B5RM00\",\"segmentId\":\"13NI00B5RM013NID0B5RM00900\"}},{\"id\":692561,\"licenseColor\":9,\"picLicense\":null,\"originalColor\":0,\"originalType\":1,\"longitude\":117.0962648,\"latitude\":36.6449813,\"speed\":10.77,\"altitude\":0.0,\"courseAngle\":271.0,\"baseLocation\":0,\"waitingTime\":35,\"stopNum\":1,\"roadnet\":{\"crossId\":\"13NHC0B5R40\",\"laneId\":\"null\",\"rid\":\"null\",\"segmentId\":\"null\"}},{\"id\":692571,\"licenseColor\":0,\"picLicense\":\"鲁R660WD\",\"originalColor\":9,\"originalType\":1,\"longitude\":117.0863272,\"latitude\":36.6422532,\"speed\":37.8,\"altitude\":0.0,\"courseAngle\":230.0,\"baseLocation\":0,\"waitingTime\":0,\"stopNum\":0,\"roadnet\":{\"crossId\":\"null\",\"laneId\":\"13NGH0B5RC013NF80B5QN0090012\",\"rid\":\"13NGH0B5RC013NF80B5QN00\",\"segmentId\":\"13NGH0B5RC013NF80B5QN00900\"}},{\"id\":692575,\"licenseColor\":9,\"picLicense\":null,\"originalColor\":0,\"originalType\":1,\"longitude\":117.09561029999999,\"latitude\":36.6450442,\"speed\":33.92,\"altitude\":0.0,\"courseAngle\":269.0,\"baseLocation\":0,\"waitingTime\":32,\"stopNum\":1,\"roadnet\":{\"crossId\":\"13NHC0B5R40\",\"laneId\":\"13NID0B5RM013NI00B5RM0010013\",\"rid\":\"13NID0B5RM013NI00B5RM00\",\"segmentId\":\"13NID0B5RM013NI00B5RM00100\"}},{\"id\":692589,\"licenseColor\":9,\"picLicense\":null,\"originalColor\":0,\"originalType\":1,\"longitude\":117.09573449999999,\"latitude\":36.6450289,\"speed\":42.56,\"altitude\":0.0,\"courseAngle\":265.0,\"baseLocation\":0,\"waitingTime\":29,\"stopNum\":1,\"roadnet\":{\"crossId\":\"13NHC0B5R40\",\"laneId\":\"null\",\"rid\":\"null\",\"segmentId\":\"null\"}},{\"id\":692590,\"licenseColor\":9,\"picLicense\":null,\"originalColor\":0,\"originalType\":1,\"longitude\":117.09637629999999,\"latitude\":36.6449796,\"speed\":6.92,\"altitude\":0.0,\"courseAngle\":272.0,\"baseLocation\":0,\"waitingTime\":30,\"stopNum\":1,\"roadnet\":{\"crossId\":\"13NHC0B5R40\",\"laneId\":\"13NH20B5RH013NID0B5RM0090011\",\"rid\":\"13NH20B5RH013NID0B5RM00\",\"segmentId\":\"13NH20B5RH013NID0B5RM00900\"}},{\"id\":692596,\"licenseColor\":0,\"picLicense\":\"鲁AZ072Q\",\"originalColor\":0,\"originalType\":1,\"longitude\":117.0864763,\"latitude\":36.6423183,\"speed\":45.72,\"altitude\":0.0,\"courseAngle\":230.0,\"baseLocation\":0,\"waitingTime\":0,\"stopNum\":0,\"roadnet\":{\"crossId\":\"null\",\"laneId\":\"13NGH0B5RC013NF80B5QN0090011\",\"rid\":\"13NGH0B5RC013NF80B5QN00\",\"segmentId\":\"13NGH0B5RC013NF80B5QN00900\"}},{\"id\":692597,\"licenseColor\":0,\"picLicense\":\"鲁A68SZ7\",\"originalColor\":0,\"originalType\":1,\"longitude\":117.08620839999999,\"latitude\":36.642176,\"speed\":35.25,\"altitude\":0.0,\"courseAngle\":228.0,\"baseLocation\":0,\"waitingTime\":0,\"stopNum\":0,\"roadnet\":{\"crossId\":\"13NF80B5QN0\",\"laneId\":\"13NGH0B5RC013NF80B5QN0090012\",\"rid\":\"13NGH0B5RC013NF80B5QN00\",\"segmentId\":\"13NGH0B5RC013NF80B5QN00900\"}},{\"id\":692598,\"licenseColor\":9,\"picLicense\":null,\"originalColor\":0,\"originalType\":1,\"longitude\":117.0904463,\"latitude\":36.644238,\"speed\":21.57,\"altitude\":0.0,\"courseAngle\":243.0,\"baseLocation\":0,\"waitingTime\":0,\"stopNum\":0,\"roadnet\":{\"crossId\":\"13NGH0B5RC0\",\"laneId\":\"13NI00B5RM013NGH0B5RC0090013\",\"rid\":\"13NI00B5RM013NGH0B5RC00\",\"segmentId\":\"13NI00B5RM013NGH0B5RC00900\"}},{\"id\":692666,\"licenseColor\":9,\"picLicense\":null,\"originalColor\":0,\"originalType\":6,\"longitude\":117.08993249999999,\"latitude\":36.6437558,\"speed\":20.92,\"altitude\":0.0,\"courseAngle\":152.0,\"baseLocation\":0,\"waitingTime\":12,\"stopNum\":1,\"roadnet\":{\"crossId\":\"13NGH0B5RC0\",\"laneId\":\"13NGH0B5RC013NEP0B5QJ0010013\",\"rid\":\"13NGH0B5RC013NEP0B5QJ00\",\"segmentId\":\"13NGH0B5RC013NEP0B5QJ00100\"}},{\"id\":692609,\"licenseColor\":9,\"picLicense\":null,\"originalColor\":0,\"originalType\":1,\"longitude\":117.096519,\"latitude\":36.6449742,\"speed\":10.44,\"altitude\":0.0,\"courseAngle\":272.0,\"baseLocation\":0,\"waitingTime\":28,\"stopNum\":1,\"roadnet\":{\"crossId\":\"null\",\"laneId\":\"13NH20B5RH013NID0B5RM0020011\",\"rid\":\"13NH20B5RH013NID0B5RM00\",\"segmentId\":\"13NH20B5RH013NID0B5RM00200\"}},{\"id\":692612,\"licenseColor\":0,\"picLicense\":\"鲁A7L65S\",\"originalColor\":0,\"originalType\":1,\"longitude\":117.0876517,\"latitude\":36.6430237,\"speed\":41.51,\"altitude\":0.0,\"courseAngle\":236.0,\"baseLocation\":0,\"waitingTime\":0,\"stopNum\":0,\"roadnet\":{\"crossId\":\"null\",\"laneId\":\"13NGH0B5RC013NF80B5QN0026011\",\"rid\":\"13NGH0B5RC013NF80B5QN00\",\"segmentId\":\"13NGH0B5RC013NF80B5QN00260\"}},{\"id\":692613,\"licenseColor\":0,\"picLicense\":\"鲁A052DT\",\"originalColor\":0,\"originalType\":1,\"longitude\":117.090043,\"latitude\":36.6439136,\"speed\":16.38,\"altitude\":0.0,\"courseAngle\":344.0,\"baseLocation\":0,\"waitingTime\":25,\"stopNum\":1,\"roadnet\":{\"crossId\":\"13NGH0B5RC0\",\"laneId\":\"null\",\"rid\":\"null\",\"segmentId\":\"null\"}},{\"id\":692620,\"licenseColor\":0,\"picLicense\":\"鲁A6Y508\",\"originalColor\":0,\"originalType\":1,\"longitude\":117.0896879,\"latitude\":36.6438367,\"speed\":5.22,\"altitude\":0.0,\"courseAngle\":68.0,\"baseLocation\":0,\"waitingTime\":0,\"stopNum\":0,\"roadnet\":{\"crossId\":\"13NGH0B5RC0\",\"laneId\":\"13NF80B5QN013NGH0B5RC0090014\",\"rid\":\"13NF80B5QN013NGH0B5RC00\",\"segmentId\":\"13NF80B5QN013NGH0B5RC00900\"}},{\"id\":692622,\"licenseColor\":0,\"picLicense\":\"鲁A9337Z\",\"originalColor\":0,\"originalType\":1,\"longitude\":117.0893905,\"latitude\":36.643755999999996,\"speed\":23.58,\"altitude\":0.0,\"courseAngle\":63.0,\"baseLocation\":0,\"waitingTime\":0,\"stopNum\":0,\"roadnet\":{\"crossId\":\"null\",\"laneId\":\"13NF80B5QN013NGH0B5RC0030013\",\"rid\":\"13NF80B5QN013NGH0B5RC00\",\"segmentId\":\"13NF80B5QN013NGH0B5RC00300\"}},{\"id\":692625,\"licenseColor\":4,\"picLicense\":\"鲁ADF6931\",\"originalColor\":1,\"originalType\":1,\"longitude\":117.0876761,\"latitude\":36.6430856,\"speed\":49.54,\"altitude\":0.0,\"courseAngle\":236.0,\"baseLocation\":0,\"waitingTime\":0,\"stopNum\":0,\"roadnet\":{\"crossId\":\"null\",\"laneId\":\"13NGH0B5RC013NF80B5QN0026012\",\"rid\":\"13NGH0B5RC013NF80B5QN00\",\"segmentId\":\"13NGH0B5RC013NF80B5QN00260\"}},{\"id\":692627,\"licenseColor\":9,\"picLicense\":null,\"originalColor\":0,\"originalType\":1,\"longitude\":117.09650149999999,\"latitude\":36.6449144,\"speed\":38.78,\"altitude\":0.0,\"courseAngle\":94.0,\"baseLocation\":0,\"waitingTime\":0,\"stopNum\":0,\"roadnet\":{\"crossId\":\"13NHC0B5R40\",\"laneId\":\"13NID0B5RM013NH20B5RH0020012\",\"rid\":\"13NID0B5RM013NH20B5RH00\",\"segmentId\":\"13NID0B5RM013NH20B5RH00200\"}},{\"id\":692700,\"licenseColor\":9,\"picLicense\":null,\"originalColor\":0,\"originalType\":1,\"longitude\":117.09621589999999,\"latitude\":36.6447019,\"speed\":19.77,\"altitude\":0.0,\"courseAngle\":133.0,\"baseLocation\":0,\"waitingTime\":0,\"stopNum\":0,\"roadnet\":{\"crossId\":\"null\",\"laneId\":\"13NID0B5RM013NHC0B5R40020011\",\"rid\":\"13NID0B5RM013NHC0B5R400\",\"segmentId\":\"13NID0B5RM013NHC0B5R400200\"}},{\"id\":692691,\"licenseColor\":9,\"picLicense\":null,\"originalColor\":0,\"originalType\":1,\"longitude\":117.0886905,\"latitude\":36.643434,\"speed\":49.11,\"altitude\":0.0,\"courseAngle\":60.0,\"baseLocation\":0,\"waitingTime\":0,\"stopNum\":0,\"roadnet\":{\"crossId\":\"null\",\"laneId\":\"13NF80B5QN013NGH0B5RC0026013\",\"rid\":\"13NF80B5QN013NGH0B5RC00\",\"segmentId\":\"13NF80B5QN013NGH0B5RC00260\"}},{\"id\":692692,\"licenseColor\":9,\"picLicense\":null,\"originalColor\":0,\"originalType\":1,\"longitude\":117.0965153,\"latitude\":36.6450208,\"speed\":15.23,\"altitude\":0.0,\"courseAngle\":272.0,\"baseLocation\":0,\"waitingTime\":0,\"stopNum\":0,\"roadnet\":{\"crossId\":\"null\",\"laneId\":\"13NH20B5RH013NID0B5RM0020013\",\"rid\":\"13NH20B5RH013NID0B5RM00\",\"segmentId\":\"13NH20B5RH013NID0B5RM00200\"}},{\"id\":692694,\"licenseColor\":9,\"picLicense\":null,\"originalColor\":0,\"originalType\":1,\"longitude\":117.08527459999999,\"latitude\":36.6414798,\"speed\":44.28,\"altitude\":0.0,\"courseAngle\":52.0,\"baseLocation\":0,\"waitingTime\":0,\"stopNum\":0,\"roadnet\":{\"crossId\":\"null\",\"laneId\":\"13NED0B5Q9013NF80B5QN0024011\",\"rid\":\"13NED0B5Q9013NF80B5QN00\",\"segmentId\":\"13NED0B5Q9013NF80B5QN00240\"}},{\"id\":692695,\"licenseColor\":9,\"picLicense\":null,\"originalColor\":0,\"originalType\":1,\"longitude\":117.09014619999999,\"latitude\":36.6436576,\"speed\":9.94,\"altitude\":0.0,\"courseAngle\":338.0,\"baseLocation\":0,\"waitingTime\":3,\"stopNum\":1,\"roadnet\":{\"crossId\":\"13NGH0B5RC0\",\"laneId\":\"13NEP0B5QJ013NGH0B5RC0090012\",\"rid\":\"13NEP0B5QJ013NGH0B5RC00\",\"segmentId\":\"13NEP0B5QJ013NGH0B5RC00900\"}},{\"id\":692696,\"licenseColor\":0,\"picLicense\":\"鲁A5070E\",\"originalColor\":0,\"originalType\":1,\"longitude\":117.0899073,\"latitude\":36.6441355,\"speed\":15.52,\"altitude\":0.0,\"courseAngle\":153.0,\"baseLocation\":0,\"waitingTime\":0,\"stopNum\":0,\"roadnet\":{\"crossId\":\"13NGH0B5RC0\",\"laneId\":\"null\",\"rid\":\"null\",\"segmentId\":\"null\"}},{\"id\":692697,\"licenseColor\":9,\"picLicense\":null,\"originalColor\":0,\"originalType\":1,\"longitude\":117.0898062,\"latitude\":36.6441331,\"speed\":14.22,\"altitude\":0.0,\"courseAngle\":168.0,\"baseLocation\":0,\"waitingTime\":0,\"stopNum\":0,\"roadnet\":{\"crossId\":\"13NGH0B5RC0\",\"laneId\":\"null\",\"rid\":\"null\",\"segmentId\":\"null\"}},{\"id\":692698,\"licenseColor\":9,\"picLicense\":null,\"originalColor\":0,\"originalType\":1,\"longitude\":117.0866956,\"latitude\":36.6424611,\"speed\":42.95,\"altitude\":0.0,\"courseAngle\":231.0,\"baseLocation\":0,\"waitingTime\":0,\"stopNum\":0,\"roadnet\":{\"crossId\":\"null\",\"laneId\":\"13NGH0B5RC013NF80B5QN0030011\",\"rid\":\"13NGH0B5RC013NF80B5QN00\",\"segmentId\":\"13NGH0B5RC013NF80B5QN00300\"}},{\"id\":692699,\"licenseColor\":9,\"picLicense\":null,\"originalColor\":0,\"originalType\":1,\"longitude\":117.0884938,\"latitude\":36.6434931,\"speed\":53.1,\"altitude\":0.0,\"courseAngle\":240.0,\"baseLocation\":0,\"waitingTime\":0,\"stopNum\":0,\"roadnet\":{\"crossId\":\"null\",\"laneId\":\"13NGH0B5RC013NF80B5QN0024013\",\"rid\":\"13NGH0B5RC013NF80B5QN00\",\"segmentId\":\"13NGH0B5RC013NF80B5QN00240\"}},{\"id\":692689,\"licenseColor\":9,\"picLicense\":null,\"originalColor\":0,\"originalType\":1,\"longitude\":117.0963209,\"latitude\":36.645032,\"speed\":21.6,\"altitude\":0.0,\"courseAngle\":272.0,\"baseLocation\":0,\"waitingTime\":0,\"stopNum\":0,\"roadnet\":{\"crossId\":\"13NHC0B5R40\",\"laneId\":\"13NH20B5RH013NID0B5RM0090013\",\"rid\":\"13NH20B5RH013NID0B5RM00\",\"segmentId\":\"13NH20B5RH013NID0B5RM00900\"}},{\"id\":692701,\"licenseColor\":4,\"picLicense\":\"鲁AD17763\",\"originalColor\":3,\"originalType\":1,\"longitude\":117.08989589999999,\"latitude\":36.6442044,\"speed\":14.19,\"altitude\":0.0,\"courseAngle\":161.0,\"baseLocation\":0,\"waitingTime\":0,\"stopNum\":0,\"roadnet\":{\"crossId\":\"13NGH0B5RC0\",\"laneId\":\"null\",\"rid\":\"null\",\"segmentId\":\"null\"}},{\"id\":692703,\"licenseColor\":9,\"picLicense\":null,\"originalColor\":0,\"originalType\":1,\"longitude\":117.08695309999999,\"latitude\":36.642652,\"speed\":49.36,\"altitude\":0.0,\"courseAngle\":232.0,\"baseLocation\":0,\"waitingTime\":0,\"stopNum\":0,\"roadnet\":{\"crossId\":\"null\",\"laneId\":\"13NGH0B5RC013NF80B5QN0030012\",\"rid\":\"13NGH0B5RC013NF80B5QN00\",\"segmentId\":\"13NGH0B5RC013NF80B5QN00300\"}},{\"id\":692704,\"licenseColor\":9,\"picLicense\":null,\"originalColor\":0,\"originalType\":1,\"longitude\":117.0864172,\"latitude\":36.6422008,\"speed\":52.02,\"altitude\":0.0,\"courseAngle\":50.0,\"baseLocation\":0,\"waitingTime\":0,\"stopNum\":0,\"roadnet\":{\"crossId\":\"null\",\"laneId\":\"13NF80B5QN013NGH0B5RC0010012\",\"rid\":\"13NF80B5QN013NGH0B5RC00\",\"segmentId\":\"13NF80B5QN013NGH0B5RC00100\"}},{\"id\":692705,\"licenseColor\":9,\"picLicense\":null,\"originalColor\":0,\"originalType\":1,\"longitude\":117.09662549999999,\"latitude\":36.6450214,\"speed\":16.02,\"altitude\":0.0,\"courseAngle\":272.0,\"baseLocation\":0,\"waitingTime\":0,\"stopNum\":0,\"roadnet\":{\"crossId\":\"null\",\"laneId\":\"13NH20B5RH013NID0B5RM0020013\",\"rid\":\"13NH20B5RH013NID0B5RM00\",\"segmentId\":\"13NH20B5RH013NID0B5RM00200\"}},{\"id\":692707,\"licenseColor\":9,\"picLicense\":null,\"originalColor\":0,\"originalType\":6,\"longitude\":117.0859555,\"latitude\":36.642071099999995,\"speed\":27.94,\"altitude\":0.0,\"courseAngle\":228.0,\"baseLocation\":0,\"waitingTime\":0,\"stopNum\":0,\"roadnet\":{\"crossId\":\"13NF80B5QN0\",\"laneId\":\"null\",\"rid\":\"null\",\"segmentId\":\"null\"}},{\"id\":692708,\"licenseColor\":9,\"picLicense\":null,\"originalColor\":0,\"originalType\":1,\"longitude\":117.0861223,\"latitude\":36.6417394,\"speed\":4.32,\"altitude\":0.0,\"courseAngle\":321.0,\"baseLocation\":0,\"waitingTime\":0,\"stopNum\":0,\"roadnet\":{\"crossId\":\"13NF80B5QN0\",\"laneId\":\"13NDT0B5Q9013NF80B5QN0090012\",\"rid\":\"13NDT0B5Q9013NF80B5QN00\",\"segmentId\":\"13NDT0B5Q9013NF80B5QN00900\"}},{\"id\":692709,\"licenseColor\":9,\"picLicense\":null,\"originalColor\":0,\"originalType\":1,\"longitude\":117.0967218,\"latitude\":36.6449871,\"speed\":8.21,\"altitude\":0.0,\"courseAngle\":272.0,\"baseLocation\":0,\"waitingTime\":0,\"stopNum\":0,\"roadnet\":{\"crossId\":\"null\",\"laneId\":\"13NH20B5RH013NID0B5RM0020012\",\"rid\":\"13NH20B5RH013NID0B5RM00\",\"segmentId\":\"13NH20B5RH013NID0B5RM00200\"}},{\"id\":692582,\"licenseColor\":9,\"picLicense\":null,\"originalColor\":0,\"originalType\":1,\"longitude\":117.09027309999999,\"latitude\":36.644180299999995,\"speed\":7.96,\"altitude\":0.0,\"courseAngle\":245.0,\"baseLocation\":0,\"waitingTime\":0,\"stopNum\":0,\"roadnet\":{\"crossId\":\"13NGH0B5RC0\",\"laneId\":\"13NI00B5RM013NGH0B5RC0090013\",\"rid\":\"13NI00B5RM013NGH0B5RC00\",\"segmentId\":\"13NI00B5RM013NGH0B5RC00900\"}},{\"id\":692688,\"licenseColor\":9,\"picLicense\":null,\"originalColor\":0,\"originalType\":6,\"longitude\":117.0900394,\"latitude\":36.6442748,\"speed\":16.2,\"altitude\":0.0,\"courseAngle\":338.0,\"baseLocation\":0,\"waitingTime\":0,\"stopNum\":0,\"roadnet\":{\"crossId\":\"13NGH0B5RC0\",\"laneId\":\"13NGH0B5RC013NEH0B5RJ0010014\",\"rid\":\"13NGH0B5RC013NEH0B5RJ00\",\"segmentId\":\"13NGH0B5RC013NEH0B5RJ00100\"}},{\"id\":692687,\"licenseColor\":9,\"picLicense\":null,\"originalColor\":0,\"originalType\":4,\"longitude\":117.090184,\"latitude\":36.6440589,\"speed\":6.92,\"altitude\":0.0,\"courseAngle\":167.0,\"baseLocation\":0,\"waitingTime\":0,\"stopNum\":0,\"roadnet\":{\"crossId\":\"13NGH0B5RC0\",\"laneId\":\"null\",\"rid\":\"null\",\"segmentId\":\"null\"}},{\"id\":692686,\"licenseColor\":9,\"picLicense\":null,\"originalColor\":0,\"originalType\":6,\"longitude\":117.0856589,\"latitude\":36.6418283,\"speed\":51.34,\"altitude\":0.0,\"courseAngle\":228.0,\"baseLocation\":0,\"waitingTime\":0,\"stopNum\":0,\"roadnet\":{\"crossId\":\"13NF80B5QN0\",\"laneId\":\"13NF80B5QN013NED0B5Q90010012\",\"rid\":\"13NF80B5QN013NED0B5Q900\",\"segmentId\":\"13NF80B5QN013NED0B5Q900100\"}},{\"id\":692685,\"licenseColor\":4,\"picLicense\":\"鲁ADL5097\",\"originalColor\":0,\"originalType\":1,\"longitude\":117.085753,\"latitude\":36.6417578,\"speed\":24.52,\"altitude\":0.0,\"courseAngle\":49.0,\"baseLocation\":0,\"waitingTime\":0,\"stopNum\":0,\"roadnet\":{\"crossId\":\"13NF80B5QN0\",\"laneId\":\"13NED0B5Q9013NF80B5QN0090012\",\"rid\":\"13NED0B5Q9013NF80B5QN00\",\"segmentId\":\"13NED0B5Q9013NF80B5QN00900\"}},{\"id\":692684,\"licenseColor\":0,\"picLicense\":\"鲁A6HK00\",\"originalColor\":9,\"originalType\":1,\"longitude\":117.0857333,\"latitude\":36.6417766,\"speed\":20.63,\"altitude\":0.0,\"courseAngle\":50.0,\"baseLocation\":0,\"waitingTime\":0,\"stopNum\":0,\"roadnet\":{\"crossId\":\"13NF80B5QN0\",\"laneId\":\"13NED0B5Q9013NF80B5QN0090011\",\"rid\":\"13NED0B5Q9013NF80B5QN00\",\"segmentId\":\"13NED0B5Q9013NF80B5QN00900\"}},{\"id\":692682,\"licenseColor\":9,\"picLicense\":null,\"originalColor\":0,\"originalType\":1,\"longitude\":117.08632449999999,\"latitude\":36.6422866,\"speed\":35.61,\"altitude\":0.0,\"courseAngle\":230.0,\"baseLocation\":0,\"waitingTime\":0,\"stopNum\":0,\"roadnet\":{\"crossId\":\"null\",\"laneId\":\"13NGH0B5RC013NF80B5QN0090013\",\"rid\":\"13NGH0B5RC013NF80B5QN00\",\"segmentId\":\"13NGH0B5RC013NF80B5QN00900\"}},{\"id\":692681,\"licenseColor\":9,\"picLicense\":null,\"originalColor\":0,\"originalType\":1,\"longitude\":117.08984849999999,\"latitude\":36.6441229,\"speed\":16.38,\"altitude\":0.0,\"courseAngle\":164.0,\"baseLocation\":0,\"waitingTime\":0,\"stopNum\":0,\"roadnet\":{\"crossId\":\"13NGH0B5RC0\",\"laneId\":\"null\",\"rid\":\"null\",\"segmentId\":\"null\"}},{\"id\":692679,\"licenseColor\":9,\"picLicense\":null,\"originalColor\":0,\"originalType\":1,\"longitude\":117.08760009999999,\"latitude\":36.6428824,\"speed\":28.62,\"altitude\":0.0,\"courseAngle\":55.0,\"baseLocation\":0,\"waitingTime\":0,\"stopNum\":0,\"roadnet\":{\"crossId\":\"null\",\"laneId\":\"13NF80B5QN013NGH0B5RC0024013\",\"rid\":\"13NF80B5QN013NGH0B5RC00\",\"segmentId\":\"13NF80B5QN013NGH0B5RC00240\"}},{\"id\":692678,\"licenseColor\":9,\"picLicense\":null,\"originalColor\":0,\"originalType\":1,\"longitude\":117.08947549999999,\"latitude\":36.6437586,\"speed\":24.48,\"altitude\":0.0,\"courseAngle\":65.0,\"baseLocation\":0,\"waitingTime\":0,\"stopNum\":0,\"roadnet\":{\"crossId\":\"13NGH0B5RC0\",\"laneId\":\"13NF80B5QN013NGH0B5RC0090014\",\"rid\":\"13NF80B5QN013NGH0B5RC00\",\"segmentId\":\"13NF80B5QN013NGH0B5RC00900\"}},{\"id\":692677,\"licenseColor\":9,\"picLicense\":null,\"originalColor\":0,\"originalType\":1,\"longitude\":117.0961459,\"latitude\":36.6450329,\"speed\":27.04,\"altitude\":0.0,\"courseAngle\":272.0,\"baseLocation\":0,\"waitingTime\":0,\"stopNum\":0,\"roadnet\":{\"crossId\":\"13NHC0B5R40\",\"laneId\":\"null\",\"rid\":\"null\",\"segmentId\":\"null\"}},{\"id\":692676,\"licenseColor\":9,\"picLicense\":null,\"originalColor\":0,\"originalType\":4,\"longitude\":117.0897529,\"latitude\":36.6439622,\"speed\":3.35,\"altitude\":0.0,\"courseAngle\":143.0,\"baseLocation\":0,\"waitingTime\":11,\"stopNum\":1,\"roadnet\":{\"crossId\":\"13NGH0B5RC0\",\"laneId\":\"null\",\"rid\":\"null\",\"segmentId\":\"null\"}},{\"id\":692674,\"licenseColor\":9,\"picLicense\":null,\"originalColor\":0,\"originalType\":6,\"longitude\":117.09005049999999,\"latitude\":36.6442194,\"speed\":10.66,\"altitude\":0.0,\"courseAngle\":343.0,\"baseLocation\":0,\"waitingTime\":12,\"stopNum\":1,\"roadnet\":{\"crossId\":\"13NGH0B5RC0\",\"laneId\":\"null\",\"rid\":\"null\",\"segmentId\":\"null\"}},{\"id\":692673,\"licenseColor\":9,\"picLicense\":null,\"originalColor\":0,\"originalType\":1,\"longitude\":117.08978019999999,\"latitude\":36.644063599999996,\"speed\":8.68,\"altitude\":0.0,\"courseAngle\":192.0,\"baseLocation\":0,\"waitingTime\":10,\"stopNum\":1,\"roadnet\":{\"crossId\":\"13NGH0B5RC0\",\"laneId\":\"null\",\"rid\":\"null\",\"segmentId\":\"null\"}},{\"id\":692672,\"licenseColor\":0,\"picLicense\":\"鲁A926SF\",\"originalColor\":0,\"originalType\":1,\"longitude\":117.08624719999999,\"latitude\":36.6420823,\"speed\":43.82,\"altitude\":0.0,\"courseAngle\":51.0,\"baseLocation\":0,\"waitingTime\":0,\"stopNum\":0,\"roadnet\":{\"crossId\":\"13NF80B5QN0\",\"laneId\":\"13NF80B5QN013NGH0B5RC0010012\",\"rid\":\"13NF80B5QN013NGH0B5RC00\",\"segmentId\":\"13NF80B5QN013NGH0B5RC00100\"}},{\"id\":692670,\"licenseColor\":9,\"picLicense\":null,\"originalColor\":0,\"originalType\":1,\"longitude\":117.08970649999999,\"latitude\":36.643996099999995,\"speed\":8.5,\"altitude\":0.0,\"courseAngle\":223.0,\"baseLocation\":0,\"waitingTime\":10,\"stopNum\":1,\"roadnet\":{\"crossId\":\"13NGH0B5RC0\",\"laneId\":\"null\",\"rid\":\"null\",\"segmentId\":\"null\"}},{\"id\":692361,\"licenseColor\":9,\"picLicense\":null,\"originalColor\":0,\"originalType\":1,\"longitude\":117.08604349999999,\"latitude\":36.641774,\"speed\":1.3,\"altitude\":0.0,\"courseAngle\":318.0,\"baseLocation\":0,\"waitingTime\":91,\"stopNum\":1,\"roadnet\":{\"crossId\":\"13NF80B5QN0\",\"laneId\":\"13NDT0B5Q9013NF80B5QN0090011\",\"rid\":\"13NDT0B5Q9013NF80B5QN00\",\"segmentId\":\"13NDT0B5Q9013NF80B5QN00900\"}},{\"id\":692491,\"licenseColor\":9,\"picLicense\":null,\"originalColor\":0,\"originalType\":1,\"longitude\":117.09548389999999,\"latitude\":36.6449657,\"speed\":41.01,\"altitude\":0.0,\"courseAngle\":89.0,\"baseLocation\":0,\"waitingTime\":44,\"stopNum\":1,\"roadnet\":{\"crossId\":\"null\",\"laneId\":\"13NI00B5RM013NID0B5RM0090011\",\"rid\":\"13NI00B5RM013NID0B5RM00\",\"segmentId\":\"13NI00B5RM013NID0B5RM00900\"}},{\"id\":692487,\"licenseColor\":9,\"picLicense\":null,\"originalColor\":0,\"originalType\":1,\"longitude\":117.0958627,\"latitude\":36.6450111,\"speed\":22.07,\"altitude\":0.0,\"courseAngle\":271.0,\"baseLocation\":0,\"waitingTime\":56,\"stopNum\":1,\"roadnet\":{\"crossId\":\"13NHC0B5R40\",\"laneId\":\"null\",\"rid\":\"null\",\"segmentId\":\"null\"}},{\"id\":692485,\"licenseColor\":9,\"picLicense\":null,\"originalColor\":0,\"originalType\":1,\"longitude\":117.0899091,\"latitude\":36.6439741,\"speed\":20.42,\"altitude\":0.0,\"courseAngle\":162.0,\"baseLocation\":0,\"waitingTime\":58,\"stopNum\":1,\"roadnet\":{\"crossId\":\"13NGH0B5RC0\",\"laneId\":\"null\",\"rid\":\"null\",\"segmentId\":\"null\"}},{\"id\":692471,\"licenseColor\":0,\"picLicense\":\"鲁A91N59\",\"originalColor\":0,\"originalType\":1,\"longitude\":117.0899151,\"latitude\":36.6440504,\"speed\":9.94,\"altitude\":0.0,\"courseAngle\":165.0,\"baseLocation\":0,\"waitingTime\":65,\"stopNum\":1,\"roadnet\":{\"crossId\":\"13NGH0B5RC0\",\"laneId\":\"null\",\"rid\":\"null\",\"segmentId\":\"null\"}},{\"id\":692460,\"licenseColor\":0,\"picLicense\":\"鲁AZ072Q\",\"originalColor\":0,\"originalType\":1,\"longitude\":117.08724129999999,\"latitude\":36.6428262,\"speed\":48.53,\"altitude\":0.0,\"courseAngle\":234.0,\"baseLocation\":0,\"waitingTime\":0,\"stopNum\":0,\"roadnet\":{\"crossId\":\"null\",\"laneId\":\"13NGH0B5RC013NF80B5QN0028012\",\"rid\":\"13NGH0B5RC013NF80B5QN00\",\"segmentId\":\"13NGH0B5RC013NF80B5QN00280\"}},{\"id\":692417,\"licenseColor\":0,\"picLicense\":\"鲁A297DP\",\"originalColor\":0,\"originalType\":1,\"longitude\":117.0900719,\"latitude\":36.643642199999995,\"speed\":38.31,\"altitude\":0.0,\"courseAngle\":161.0,\"baseLocation\":0,\"waitingTime\":78,\"stopNum\":1,\"roadnet\":{\"crossId\":\"13NGH0B5RC0\",\"laneId\":\"13NGH0B5RC013NEP0B5QJ0010011\",\"rid\":\"13NGH0B5RC013NEP0B5QJ00\",\"segmentId\":\"13NGH0B5RC013NEP0B5QJ00100\"}},{\"id\":692410,\"licenseColor\":9,\"picLicense\":null,\"originalColor\":0,\"originalType\":6,\"longitude\":117.086047,\"latitude\":36.6418731,\"speed\":0.87,\"altitude\":0.0,\"courseAngle\":58.0,\"baseLocation\":0,\"waitingTime\":61,\"stopNum\":1,\"roadnet\":{\"crossId\":\"13NF80B5QN0\",\"laneId\":\"null\",\"rid\":\"null\",\"segmentId\":\"null\"}},{\"id\":692402,\"licenseColor\":0,\"picLicense\":\"鲁A05G8R\",\"originalColor\":0,\"originalType\":1,\"longitude\":117.08569109999999,\"latitude\":36.6417947,\"speed\":53.28,\"altitude\":0.0,\"courseAngle\":230.0,\"baseLocation\":0,\"waitingTime\":0,\"stopNum\":0,\"roadnet\":{\"crossId\":\"13NF80B5QN0\",\"laneId\":\"13NF80B5QN013NED0B5Q90010011\",\"rid\":\"13NF80B5QN013NED0B5Q900\",\"segmentId\":\"13NF80B5QN013NED0B5Q900100\"}},{\"id\":692395,\"licenseColor\":9,\"picLicense\":null,\"originalColor\":0,\"originalType\":1,\"longitude\":117.0860929,\"latitude\":36.641721499999996,\"speed\":1.26,\"altitude\":0.0,\"courseAngle\":318.0,\"baseLocation\":0,\"waitingTime\":84,\"stopNum\":1,\"roadnet\":{\"crossId\":\"13NF80B5QN0\",\"laneId\":\"13NDT0B5Q9013NF80B5QN0090011\",\"rid\":\"13NDT0B5Q9013NF80B5QN00\",\"segmentId\":\"13NDT0B5Q9013NF80B5QN00900\"}},{\"id\":692379,\"licenseColor\":0,\"picLicense\":\"默A00000\",\"originalColor\":0,\"originalType\":1,\"longitude\":117.0860587,\"latitude\":36.6418034,\"speed\":0.04,\"altitude\":0.0,\"courseAngle\":321.0,\"baseLocation\":0,\"waitingTime\":86,\"stopNum\":1,\"roadnet\":{\"crossId\":\"13NF80B5QN0\",\"laneId\":\"13NDT0B5Q9013NF80B5QN0090012\",\"rid\":\"13NDT0B5Q9013NF80B5QN00\",\"segmentId\":\"13NDT0B5Q9013NF80B5QN00900\"}},{\"id\":692376,\"licenseColor\":4,\"picLicense\":\"鲁AFF9132\",\"originalColor\":0,\"originalType\":1,\"longitude\":117.08997819999999,\"latitude\":36.6440947,\"speed\":9.08,\"altitude\":0.0,\"courseAngle\":342.0,\"baseLocation\":0,\"waitingTime\":82,\"stopNum\":1,\"roadnet\":{\"crossId\":\"13NGH0B5RC0\",\"laneId\":\"null\",\"rid\":\"null\",\"segmentId\":\"null\"}},{\"id\":692555,\"licenseColor\":0,\"picLicense\":\"鲁A99G77\",\"originalColor\":0,\"originalType\":1,\"longitude\":117.08957459999999,\"latitude\":36.6438205,\"speed\":6.63,\"altitude\":0.0,\"courseAngle\":64.0,\"baseLocation\":0,\"waitingTime\":0,\"stopNum\":0,\"roadnet\":{\"crossId\":\"13NGH0B5RC0\",\"laneId\":\"13NF80B5QN013NGH0B5RC0090013\",\"rid\":\"13NF80B5QN013NGH0B5RC00\",\"segmentId\":\"13NF80B5QN013NGH0B5RC00900\"}},{\"id\":692351,\"licenseColor\":0,\"picLicense\":\"鲁A8DK00\",\"originalColor\":0,\"originalType\":1,\"longitude\":117.0957116,\"latitude\":36.644903299999996,\"speed\":49.11,\"altitude\":0.0,\"courseAngle\":91.0,\"baseLocation\":0,\"waitingTime\":40,\"stopNum\":1,\"roadnet\":{\"crossId\":\"13NHC0B5R40\",\"laneId\":\"13NI00B5RM013NID0B5RM0090013\",\"rid\":\"13NI00B5RM013NID0B5RM00\",\"segmentId\":\"13NI00B5RM013NID0B5RM00900\"}},{\"id\":692338,\"licenseColor\":4,\"picLicense\":\"豫AF73056\",\"originalColor\":0,\"originalType\":1,\"longitude\":117.0957954,\"latitude\":36.6449554,\"speed\":43.71,\"altitude\":0.0,\"courseAngle\":92.0,\"baseLocation\":0,\"waitingTime\":52,\"stopNum\":1,\"roadnet\":{\"crossId\":\"13NHC0B5R40\",\"laneId\":\"null\",\"rid\":\"null\",\"segmentId\":\"null\"}},{\"id\":692323,\"licenseColor\":4,\"picLicense\":\"鲁AD28000\",\"originalColor\":2,\"originalType\":1,\"longitude\":117.0964968,\"latitude\":36.6448855,\"speed\":56.99,\"altitude\":0.0,\"courseAngle\":94.0,\"baseLocation\":0,\"waitingTime\":55,\"stopNum\":1,\"roadnet\":{\"crossId\":\"13NHC0B5R40\",\"laneId\":\"13NID0B5RM013NH20B5RH0020013\",\"rid\":\"13NID0B5RM013NH20B5RH00\",\"segmentId\":\"13NID0B5RM013NH20B5RH00200\"}},{\"id\":692302,\"licenseColor\":4,\"picLicense\":\"鲁AD63366\",\"originalColor\":1,\"originalType\":1,\"longitude\":117.0961882,\"latitude\":36.6448927,\"speed\":52.17,\"altitude\":0.0,\"courseAngle\":91.0,\"baseLocation\":0,\"waitingTime\":46,\"stopNum\":1,\"roadnet\":{\"crossId\":\"13NHC0B5R40\",\"laneId\":\"null\",\"rid\":\"null\",\"segmentId\":\"null\"}},{\"id\":692285,\"licenseColor\":0,\"picLicense\":\"鲁A75DW2\",\"originalColor\":9,\"originalType\":1,\"longitude\":117.0900207,\"latitude\":36.6441325,\"speed\":13.18,\"altitude\":0.0,\"courseAngle\":125.0,\"baseLocation\":0,\"waitingTime\":116,\"stopNum\":1,\"roadnet\":{\"crossId\":\"13NGH0B5RC0\",\"laneId\":\"null\",\"rid\":\"null\",\"segmentId\":\"null\"}},{\"id\":692269,\"licenseColor\":0,\"picLicense\":\"鲁AW63T5\",\"originalColor\":9,\"originalType\":1,\"longitude\":117.09010769999999,\"latitude\":36.6440738,\"speed\":13.04,\"altitude\":0.0,\"courseAngle\":104.0,\"baseLocation\":0,\"waitingTime\":122,\"stopNum\":1,\"roadnet\":{\"crossId\":\"13NGH0B5RC0\",\"laneId\":\"null\",\"rid\":\"null\",\"segmentId\":\"null\"}},{\"id\":692265,\"licenseColor\":9,\"picLicense\":null,\"originalColor\":0,\"originalType\":1,\"longitude\":117.0857655,\"latitude\":36.642134399999996,\"speed\":0.26,\"altitude\":0.0,\"courseAngle\":155.0,\"baseLocation\":0,\"waitingTime\":126,\"stopNum\":1,\"roadnet\":{\"crossId\":\"13NF80B5QN0\",\"laneId\":\"13NDG0B5RI013NF80B5QN0033011\",\"rid\":\"13NDG0B5RI013NF80B5QN00\",\"segmentId\":\"13NDG0B5RI013NF80B5QN00330\"}},{\"id\":692256,\"licenseColor\":9,\"picLicense\":null,\"originalColor\":0,\"originalType\":1,\"longitude\":117.08580359999999,\"latitude\":36.642073499999995,\"speed\":1.08,\"altitude\":0.0,\"courseAngle\":145.0,\"baseLocation\":0,\"waitingTime\":127,\"stopNum\":1,\"roadnet\":{\"crossId\":\"13NF80B5QN0\",\"laneId\":\"13NDG0B5RI013NF80B5QN0090011\",\"rid\":\"13NDG0B5RI013NF80B5QN00\",\"segmentId\":\"13NDG0B5RI013NF80B5QN00900\"}},{\"id\":692115,\"licenseColor\":0,\"picLicense\":\"鲁AM7Q60\",\"originalColor\":9,\"originalType\":1,\"longitude\":117.09608619999999,\"latitude\":36.6449211,\"speed\":45.22,\"altitude\":0.0,\"courseAngle\":92.0,\"baseLocation\":0,\"waitingTime\":155,\"stopNum\":2,\"roadnet\":{\"crossId\":\"13NHC0B5R40\",\"laneId\":\"null\",\"rid\":\"null\",\"segmentId\":\"null\"}},{\"id\":692068,\"licenseColor\":0,\"picLicense\":\"鲁M6J789\",\"originalColor\":0,\"originalType\":1,\"longitude\":117.08800769999999,\"latitude\":36.6432068,\"speed\":33.81,\"altitude\":0.0,\"courseAngle\":237.0,\"baseLocation\":0,\"waitingTime\":170,\"stopNum\":1,\"roadnet\":{\"crossId\":\"null\",\"laneId\":\"13NGH0B5RC013NF80B5QN0024011\",\"rid\":\"13NGH0B5RC013NF80B5QN00\",\"segmentId\":\"13NGH0B5RC013NF80B5QN00240\"}},{\"id\":691986,\"licenseColor\":9,\"picLicense\":null,\"originalColor\":0,\"originalType\":4,\"longitude\":117.0899694,\"latitude\":36.6443247,\"speed\":0.0,\"altitude\":0.0,\"courseAngle\":339.0,\"baseLocation\":0,\"waitingTime\":192,\"stopNum\":1,\"roadnet\":{\"crossId\":\"13NGH0B5RC0\",\"laneId\":\"null\",\"rid\":\"null\",\"segmentId\":\"null\"}},{\"id\":692543,\"licenseColor\":9,\"picLicense\":null,\"originalColor\":0,\"originalType\":1,\"longitude\":117.08645039999999,\"latitude\":36.6423394,\"speed\":44.25,\"altitude\":0.0,\"courseAngle\":230.0,\"baseLocation\":0,\"waitingTime\":37,\"stopNum\":1,\"roadnet\":{\"crossId\":\"null\",\"laneId\":\"13NGH0B5RC013NF80B5QN0090012\",\"rid\":\"13NGH0B5RC013NF80B5QN00\",\"segmentId\":\"13NGH0B5RC013NF80B5QN00900\"}},{\"id\":692529,\"licenseColor\":4,\"picLicense\":\"鲁AD90217\",\"originalColor\":0,\"originalType\":1,\"longitude\":117.0900071,\"latitude\":36.6440123,\"speed\":13.11,\"altitude\":0.0,\"courseAngle\":342.0,\"baseLocation\":0,\"waitingTime\":43,\"stopNum\":1,\"roadnet\":{\"crossId\":\"13NGH0B5RC0\",\"laneId\":\"null\",\"rid\":\"null\",\"segmentId\":\"null\"}},{\"id\":692533,\"licenseColor\":0,\"picLicense\":\"鲁A5M506\",\"originalColor\":1,\"originalType\":1,\"longitude\":117.0867394,\"latitude\":36.6425231,\"speed\":51.45,\"altitude\":0.0,\"courseAngle\":231.0,\"baseLocation\":0,\"waitingTime\":0,\"stopNum\":0,\"roadnet\":{\"crossId\":\"null\",\"laneId\":\"13NGH0B5RC013NF80B5QN0030012\",\"rid\":\"13NGH0B5RC013NF80B5QN00\",\"segmentId\":\"13NGH0B5RC013NF80B5QN00300\"}},{\"id\":692537,\"licenseColor\":0,\"picLicense\":\"鲁A278Z1\",\"originalColor\":0,\"originalType\":1,\"longitude\":117.08533899999999,\"latitude\":36.641602,\"speed\":45.87,\"altitude\":0.0,\"courseAngle\":231.0,\"baseLocation\":0,\"waitingTime\":0,\"stopNum\":0,\"roadnet\":{\"crossId\":\"null\",\"laneId\":\"13NF80B5QN013NED0B5Q90010012\",\"rid\":\"13NF80B5QN013NED0B5Q900\",\"segmentId\":\"13NF80B5QN013NED0B5Q900100\"}},{\"id\":692538,\"licenseColor\":9,\"picLicense\":null,\"originalColor\":0,\"originalType\":6,\"longitude\":117.0899068,\"latitude\":36.6438075,\"speed\":16.78,\"altitude\":0.0,\"courseAngle\":141.0,\"baseLocation\":0,\"waitingTime\":43,\"stopNum\":1,\"roadnet\":{\"crossId\":\"13NGH0B5RC0\",\"laneId\":\"null\",\"rid\":\"null\",\"segmentId\":\"null\"}},{\"id\":692539,\"licenseColor\":0,\"picLicense\":\"鲁AU7H50\",\"originalColor\":2,\"originalType\":1,\"longitude\":117.08968139999999,\"latitude\":36.6438614,\"speed\":1.62,\"altitude\":0.0,\"courseAngle\":65.0,\"baseLocation\":0,\"waitingTime\":7,\"stopNum\":1,\"roadnet\":{\"crossId\":\"13NGH0B5RC0\",\"laneId\":\"13NF80B5QN013NGH0B5RC0090013\",\"rid\":\"13NF80B5QN013NGH0B5RC00\",\"segmentId\":\"13NF80B5QN013NGH0B5RC00900\"}},{\"id\":692523,\"licenseColor\":0,\"picLicense\":\"鲁A7GB72\",\"originalColor\":9,\"originalType\":1,\"longitude\":117.08823699999999,\"latitude\":36.6433429,\"speed\":46.44,\"altitude\":0.0,\"courseAngle\":238.0,\"baseLocation\":0,\"waitingTime\":0,\"stopNum\":0,\"roadnet\":{\"crossId\":\"null\",\"laneId\":\"13NGH0B5RC013NF80B5QN0024012\",\"rid\":\"13NGH0B5RC013NF80B5QN00\",\"segmentId\":\"13NGH0B5RC013NF80B5QN00240\"}},{\"id\":692540,\"licenseColor\":9,\"picLicense\":null,\"originalColor\":0,\"originalType\":1,\"longitude\":117.0953457,\"latitude\":36.6449508,\"speed\":39.89,\"altitude\":0.0,\"courseAngle\":88.0,\"baseLocation\":0,\"waitingTime\":31,\"stopNum\":1,\"roadnet\":{\"crossId\":\"null\",\"laneId\":\"13NI00B5RM013NID0B5RM0020012\",\"rid\":\"13NI00B5RM013NID0B5RM00\",\"segmentId\":\"13NI00B5RM013NID0B5RM00200\"}},{\"id\":692518,\"licenseColor\":9,\"picLicense\":null,\"originalColor\":0,\"originalType\":3,\"longitude\":117.0899862,\"latitude\":36.6437656,\"speed\":0.62,\"altitude\":0.0,\"courseAngle\":161.0,\"baseLocation\":0,\"waitingTime\":52,\"stopNum\":1,\"roadnet\":{\"crossId\":\"13NGH0B5RC0\",\"laneId\":\"13NGH0B5RC013NEP0B5QJ0010012\",\"rid\":\"13NGH0B5RC013NEP0B5QJ00\",\"segmentId\":\"13NGH0B5RC013NEP0B5QJ00100\"}},{\"id\":692544,\"licenseColor\":0,\"picLicense\":\"鲁AL9221\",\"originalColor\":1,\"originalType\":1,\"longitude\":117.0899889,\"latitude\":36.6439192,\"speed\":5.08,\"altitude\":0.0,\"courseAngle\":332.0,\"baseLocation\":0,\"waitingTime\":37,\"stopNum\":1,\"roadnet\":{\"crossId\":\"13NGH0B5RC0\",\"laneId\":\"null\",\"rid\":\"null\",\"segmentId\":\"null\"}},{\"id\":692547,\"licenseColor\":0,\"picLicense\":\"鲁A0PT36\",\"originalColor\":1,\"originalType\":1,\"longitude\":117.0895608,\"latitude\":36.643845299999995,\"speed\":14.94,\"altitude\":0.0,\"courseAngle\":64.0,\"baseLocation\":0,\"waitingTime\":0,\"stopNum\":0,\"roadnet\":{\"crossId\":\"13NGH0B5RC0\",\"laneId\":\"13NF80B5QN013NGH0B5RC0090012\",\"rid\":\"13NF80B5QN013NGH0B5RC00\",\"segmentId\":\"13NF80B5QN013NGH0B5RC00900\"}},{\"id\":692508,\"licenseColor\":9,\"picLicense\":null,\"originalColor\":0,\"originalType\":1,\"longitude\":117.09522439999999,\"latitude\":36.6449017,\"speed\":38.42,\"altitude\":0.0,\"courseAngle\":87.0,\"baseLocation\":0,\"waitingTime\":35,\"stopNum\":1,\"roadnet\":{\"crossId\":\"null\",\"laneId\":\"13NI00B5RM013NID0B5RM0010013\",\"rid\":\"13NI00B5RM013NID0B5RM00\",\"segmentId\":\"13NI00B5RM013NID0B5RM00100\"}},{\"id\":692498,\"licenseColor\":9,\"picLicense\":null,\"originalColor\":0,\"originalType\":1,\"longitude\":117.09597009999999,\"latitude\":36.6449874,\"speed\":20.45,\"altitude\":0.0,\"courseAngle\":270.0,\"baseLocation\":0,\"waitingTime\":53,\"stopNum\":1,\"roadnet\":{\"crossId\":\"13NHC0B5R40\",\"laneId\":\"null\",\"rid\":\"null\",\"segmentId\":\"null\"}},{\"id\":692551,\"licenseColor\":0,\"picLicense\":\"鲁A86QF1\",\"originalColor\":3,\"originalType\":1,\"longitude\":117.08966939999999,\"latitude\":36.6438862,\"speed\":1.7,\"altitude\":0.0,\"courseAngle\":65.0,\"baseLocation\":0,\"waitingTime\":6,\"stopNum\":1,\"roadnet\":{\"crossId\":\"13NGH0B5RC0\",\"laneId\":\"13NF80B5QN013NGH0B5RC0090012\",\"rid\":\"13NF80B5QN013NGH0B5RC00\",\"segmentId\":\"13NF80B5QN013NGH0B5RC00900\"}},{\"id\":692549,\"licenseColor\":9,\"picLicense\":null,\"originalColor\":0,\"originalType\":1,\"longitude\":117.09625419999999,\"latitude\":36.645008,\"speed\":16.56,\"altitude\":0.0,\"courseAngle\":272.0,\"baseLocation\":0,\"waitingTime\":38,\"stopNum\":1,\"roadnet\":{\"crossId\":\"13NHC0B5R40\",\"laneId\":\"null\",\"rid\":\"null\",\"segmentId\":\"null\"}},{\"id\":692504,\"licenseColor\":9,\"picLicense\":null,\"originalColor\":0,\"originalType\":1,\"longitude\":117.09611459999999,\"latitude\":36.6450082,\"speed\":20.31,\"altitude\":0.0,\"courseAngle\":272.0,\"baseLocation\":0,\"waitingTime\":52,\"stopNum\":1,\"roadnet\":{\"crossId\":\"13NHC0B5R40\",\"laneId\":\"null\",\"rid\":\"null\",\"segmentId\":\"null\"}},{\"id\":692300,\"licenseColor\":0,\"picLicense\":\"鲁A5V222\",\"originalColor\":1,\"originalType\":1,\"longitude\":117.0949911,\"latitude\":36.644921599999996,\"speed\":31.58,\"altitude\":0.0,\"courseAngle\":87.0,\"baseLocation\":0,\"waitingTime\":46,\"stopNum\":1,\"roadnet\":{\"crossId\":\"13NG40B5SK0\",\"laneId\":\"13NI00B5RM013NID0B5RM0010012\",\"rid\":\"13NI00B5RM013NID0B5RM00\",\"segmentId\":\"13NI00B5RM013NID0B5RM00100\"}},{\"id\":692240,\"licenseColor\":9,\"picLicense\":null,\"originalColor\":0,\"originalType\":1,\"longitude\":117.09394449999999,\"latitude\":36.6448956,\"speed\":5.69,\"altitude\":0.0,\"courseAngle\":83.0,\"baseLocation\":0,\"waitingTime\":114,\"stopNum\":2,\"roadnet\":{\"crossId\":\"null\",\"laneId\":\"13NGH0B5RC013NI00B5RM0027011\",\"rid\":\"13NGH0B5RC013NI00B5RM00\",\"segmentId\":\"13NGH0B5RC013NI00B5RM00270\"}},{\"id\":692693,\"licenseColor\":9,\"picLicense\":null,\"originalColor\":0,\"originalType\":1,\"longitude\":117.09442449999999,\"latitude\":36.6450126,\"speed\":23.12,\"altitude\":0.0,\"courseAngle\":239.0,\"baseLocation\":0,\"waitingTime\":0,\"stopNum\":0,\"roadnet\":{\"crossId\":\"13NG40B5SK0\",\"laneId\":\"null\",\"rid\":\"null\",\"segmentId\":\"null\"}},{\"id\":692222,\"licenseColor\":9,\"picLicense\":null,\"originalColor\":0,\"originalType\":10,\"longitude\":117.0945497,\"latitude\":36.6449514,\"speed\":22.97,\"altitude\":0.0,\"courseAngle\":78.0,\"baseLocation\":0,\"waitingTime\":130,\"stopNum\":3,\"roadnet\":{\"crossId\":\"13NG40B5SK0\",\"laneId\":\"null\",\"rid\":\"null\",\"segmentId\":\"null\"}},{\"id\":692309,\"licenseColor\":9,\"picLicense\":null,\"originalColor\":0,\"originalType\":1,\"longitude\":117.09424,\"latitude\":36.6449237,\"speed\":25.67,\"altitude\":0.0,\"courseAngle\":83.0,\"baseLocation\":0,\"waitingTime\":111,\"stopNum\":3,\"roadnet\":{\"crossId\":\"13NG40B5SK0\",\"laneId\":\"13NGH0B5RC013NI00B5RM0027011\",\"rid\":\"13NGH0B5RC013NI00B5RM00\",\"segmentId\":\"13NGH0B5RC013NI00B5RM00270\"}},{\"id\":692207,\"licenseColor\":9,\"picLicense\":null,\"originalColor\":0,\"originalType\":1,\"longitude\":117.0946441,\"latitude\":36.6449905,\"speed\":18.65,\"altitude\":0.0,\"courseAngle\":53.0,\"baseLocation\":0,\"waitingTime\":132,\"stopNum\":3,\"roadnet\":{\"crossId\":\"13NG40B5SK0\",\"laneId\":\"null\",\"rid\":\"null\",\"segmentId\":\"null\"}},{\"id\":692289,\"licenseColor\":0,\"picLicense\":\"鲁AU306L\",\"originalColor\":9,\"originalType\":1,\"longitude\":117.09357519999999,\"latitude\":36.6448544,\"speed\":0.0,\"altitude\":0.0,\"courseAngle\":79.0,\"baseLocation\":0,\"waitingTime\":50,\"stopNum\":1,\"roadnet\":{\"crossId\":\"null\",\"laneId\":\"13NGH0B5RC013NI00B5RM0025011\",\"rid\":\"13NGH0B5RC013NI00B5RM00\",\"segmentId\":\"13NGH0B5RC013NI00B5RM00250\"}},{\"id\":692495,\"licenseColor\":9,\"picLicense\":null,\"originalColor\":0,\"originalType\":1,\"longitude\":117.0948123,\"latitude\":36.6449122,\"speed\":29.27,\"altitude\":0.0,\"courseAngle\":86.0,\"baseLocation\":0,\"waitingTime\":45,\"stopNum\":1,\"roadnet\":{\"crossId\":\"13NG40B5SK0\",\"laneId\":\"null\",\"rid\":\"null\",\"segmentId\":\"null\"}},{\"id\":692343,\"licenseColor\":0,\"picLicense\":\"鲁A6H380\",\"originalColor\":0,\"originalType\":1,\"longitude\":117.0937314,\"latitude\":36.6448731,\"speed\":0.15,\"altitude\":0.0,\"courseAngle\":81.0,\"baseLocation\":0,\"waitingTime\":72,\"stopNum\":2,\"roadnet\":{\"crossId\":\"null\",\"laneId\":\"13NGH0B5RC013NI00B5RM0026011\",\"rid\":\"13NGH0B5RC013NI00B5RM00\",\"segmentId\":\"13NGH0B5RC013NI00B5RM00260\"}},{\"id\":692073,\"licenseColor\":9,\"picLicense\":null,\"originalColor\":0,\"originalType\":1,\"longitude\":117.09469689999999,\"latitude\":36.6451898,\"speed\":23.91,\"altitude\":0.0,\"courseAngle\":0.0,\"baseLocation\":0,\"waitingTime\":172,\"stopNum\":4,\"roadnet\":{\"crossId\":\"13NG40B5SK0\",\"laneId\":\"13NI00B5RM013NG40B5SK0010011\",\"rid\":\"13NI00B5RM013NG40B5SK00\",\"segmentId\":\"13NI00B5RM013NG40B5SK00100\"}},{\"id\":692284,\"licenseColor\":4,\"picLicense\":\"鲁AFJ1191\",\"originalColor\":2,\"originalType\":1,\"longitude\":117.0936467,\"latitude\":36.644862599999996,\"speed\":0.11,\"altitude\":0.0,\"courseAngle\":81.0,\"baseLocation\":0,\"waitingTime\":56,\"stopNum\":1,\"roadnet\":{\"crossId\":\"null\",\"laneId\":\"13NGH0B5RC013NI00B5RM0026011\",\"rid\":\"13NGH0B5RC013NI00B5RM00\",\"segmentId\":\"13NGH0B5RC013NI00B5RM00260\"}},{\"id\":691827,\"licenseColor\":0,\"picLicense\":\"鲁VM7J02\",\"originalColor\":1,\"originalType\":1,\"longitude\":117.09437059999999,\"latitude\":36.6449334,\"speed\":21.03,\"altitude\":0.0,\"courseAngle\":84.0,\"baseLocation\":0,\"waitingTime\":203,\"stopNum\":5,\"roadnet\":{\"crossId\":\"13NG40B5SK0\",\"laneId\":\"13NGH0B5RC013NI00B5RM0027011\",\"rid\":\"13NGH0B5RC013NI00B5RM00\",\"segmentId\":\"13NGH0B5RC013NI00B5RM00270\"}},{\"id\":692388,\"licenseColor\":0,\"picLicense\":\"鲁A7F92M\",\"originalColor\":0,\"originalType\":1,\"longitude\":117.094252,\"latitude\":36.6448718,\"speed\":11.96,\"altitude\":0.0,\"courseAngle\":85.0,\"baseLocation\":0,\"waitingTime\":13,\"stopNum\":1,\"roadnet\":{\"crossId\":\"13NG40B5SK0\",\"laneId\":\"13NGH0B5RC013NI00B5RM0027013\",\"rid\":\"13NGH0B5RC013NI00B5RM00\",\"segmentId\":\"13NGH0B5RC013NI00B5RM00270\"}},{\"id\":692636,\"licenseColor\":9,\"picLicense\":null,\"originalColor\":0,\"originalType\":1,\"longitude\":117.09250229999999,\"latitude\":36.6447074,\"speed\":46.66,\"altitude\":0.0,\"courseAngle\":257.0,\"baseLocation\":0,\"waitingTime\":0,\"stopNum\":0,\"roadnet\":{\"crossId\":\"null\",\"laneId\":\"13NI00B5RM013NGH0B5RC0023011\",\"rid\":\"13NI00B5RM013NGH0B5RC00\",\"segmentId\":\"13NI00B5RM013NGH0B5RC00230\"}},{\"id\":692653,\"licenseColor\":0,\"picLicense\":\"鲁Q06069\",\"originalColor\":1,\"originalType\":1,\"longitude\":117.0938221,\"latitude\":36.6448348,\"speed\":31.86,\"altitude\":0.0,\"courseAngle\":82.0,\"baseLocation\":0,\"waitingTime\":0,\"stopNum\":0,\"roadnet\":{\"crossId\":\"null\",\"laneId\":\"13NGH0B5RC013NI00B5RM0026013\",\"rid\":\"13NGH0B5RC013NI00B5RM00\",\"segmentId\":\"13NGH0B5RC013NI00B5RM00260\"}},{\"id\":692480,\"licenseColor\":0,\"picLicense\":\"鲁AHH260\",\"originalColor\":0,\"originalType\":1,\"longitude\":117.09313809999999,\"latitude\":36.6447867,\"speed\":30.17,\"altitude\":0.0,\"courseAngle\":78.0,\"baseLocation\":0,\"waitingTime\":0,\"stopNum\":0,\"roadnet\":{\"crossId\":\"null\",\"laneId\":\"13NGH0B5RC013NI00B5RM0025011\",\"rid\":\"13NGH0B5RC013NI00B5RM00\",\"segmentId\":\"13NGH0B5RC013NI00B5RM00250\"}},{\"id\":692469,\"licenseColor\":0,\"picLicense\":\"鲁AB699P\",\"originalColor\":0,\"originalType\":1,\"longitude\":117.0942693,\"latitude\":36.644899699999996,\"speed\":37.62,\"altitude\":0.0,\"courseAngle\":83.0,\"baseLocation\":0,\"waitingTime\":0,\"stopNum\":0,\"roadnet\":{\"crossId\":\"13NG40B5SK0\",\"laneId\":\"13NGH0B5RC013NI00B5RM0027012\",\"rid\":\"13NGH0B5RC013NI00B5RM00\",\"segmentId\":\"13NGH0B5RC013NI00B5RM00270\"}},{\"id\":692515,\"licenseColor\":0,\"picLicense\":\"鲁A5A70H\",\"originalColor\":0,\"originalType\":1,\"longitude\":117.09388659999999,\"latitude\":36.6448167,\"speed\":50.44,\"altitude\":0.0,\"courseAngle\":82.0,\"baseLocation\":0,\"waitingTime\":0,\"stopNum\":0,\"roadnet\":{\"crossId\":\"null\",\"laneId\":\"13NGH0B5RC013NI00B5RM0026014\",\"rid\":\"13NGH0B5RC013NI00B5RM00\",\"segmentId\":\"13NGH0B5RC013NI00B5RM00260\"}},{\"id\":692457,\"licenseColor\":9,\"picLicense\":null,\"originalColor\":0,\"originalType\":1,\"longitude\":117.09384,\"latitude\":36.644884399999995,\"speed\":0.29,\"altitude\":0.0,\"courseAngle\":82.0,\"baseLocation\":0,\"waitingTime\":69,\"stopNum\":2,\"roadnet\":{\"crossId\":\"null\",\"laneId\":\"13NGH0B5RC013NI00B5RM0026011\",\"rid\":\"13NGH0B5RC013NI00B5RM00\",\"segmentId\":\"13NGH0B5RC013NI00B5RM00260\"}},{\"id\":692431,\"licenseColor\":0,\"picLicense\":\"鲁A3D9T6\",\"originalColor\":0,\"originalType\":1,\"longitude\":117.09469399999999,\"latitude\":36.6448812,\"speed\":38.09,\"altitude\":0.0,\"courseAngle\":84.0,\"baseLocation\":0,\"waitingTime\":0,\"stopNum\":0,\"roadnet\":{\"crossId\":\"13NG40B5SK0\",\"laneId\":\"null\",\"rid\":\"null\",\"segmentId\":\"null\"}},{\"id\":692423,\"licenseColor\":0,\"picLicense\":\"鲁AKW863\",\"originalColor\":0,\"originalType\":1,\"longitude\":117.0944116,\"latitude\":36.644886,\"speed\":18.54,\"altitude\":0.0,\"courseAngle\":85.0,\"baseLocation\":0,\"waitingTime\":15,\"stopNum\":1,\"roadnet\":{\"crossId\":\"13NG40B5SK0\",\"laneId\":\"13NGH0B5RC013NI00B5RM0027013\",\"rid\":\"13NGH0B5RC013NI00B5RM00\",\"segmentId\":\"13NGH0B5RC013NI00B5RM00270\"}},{\"id\":692516,\"licenseColor\":0,\"picLicense\":\"鲁A0M719\",\"originalColor\":0,\"originalType\":1,\"longitude\":117.0926288,\"latitude\":36.6446623,\"speed\":45.18,\"altitude\":0.0,\"courseAngle\":77.0,\"baseLocation\":0,\"waitingTime\":0,\"stopNum\":0,\"roadnet\":{\"crossId\":\"null\",\"laneId\":\"13NGH0B5RC013NI00B5RM0024012\",\"rid\":\"13NGH0B5RC013NI00B5RM00\",\"segmentId\":\"13NGH0B5RC013NI00B5RM00240\"}},{\"id\":692407,\"licenseColor\":9,\"picLicense\":null,\"originalColor\":0,\"originalType\":1,\"longitude\":117.0949617,\"latitude\":36.6449832,\"speed\":0.11,\"altitude\":0.0,\"courseAngle\":266.0,\"baseLocation\":0,\"waitingTime\":77,\"stopNum\":2,\"roadnet\":{\"crossId\":\"13NG40B5SK0\",\"laneId\":\"13NID0B5RM013NI00B5RM0090011\",\"rid\":\"13NID0B5RM013NI00B5RM00\",\"segmentId\":\"13NID0B5RM013NI00B5RM00900\"}},{\"id\":692406,\"licenseColor\":0,\"picLicense\":\"鲁AFT608\",\"originalColor\":0,\"originalType\":1,\"longitude\":117.09405849999999,\"latitude\":36.6448575,\"speed\":11.63,\"altitude\":0.0,\"courseAngle\":83.0,\"baseLocation\":0,\"waitingTime\":0,\"stopNum\":0,\"roadnet\":{\"crossId\":\"null\",\"laneId\":\"13NGH0B5RC013NI00B5RM0027013\",\"rid\":\"13NGH0B5RC013NI00B5RM00\",\"segmentId\":\"13NGH0B5RC013NI00B5RM00270\"}},{\"id\":692404,\"licenseColor\":0,\"picLicense\":\"鲁A31M0B\",\"originalColor\":0,\"originalType\":1,\"longitude\":117.0945579,\"latitude\":36.6448964,\"speed\":21.24,\"altitude\":0.0,\"courseAngle\":84.0,\"baseLocation\":0,\"waitingTime\":17,\"stopNum\":1,\"roadnet\":{\"crossId\":\"13NG40B5SK0\",\"laneId\":\"null\",\"rid\":\"null\",\"segmentId\":\"null\"}},{\"id\":692390,\"licenseColor\":0,\"picLicense\":\"鲁AV05V5\",\"originalColor\":2,\"originalType\":1,\"longitude\":117.09494559999999,\"latitude\":36.6449478,\"speed\":31.86,\"altitude\":0.0,\"courseAngle\":87.0,\"baseLocation\":0,\"waitingTime\":15,\"stopNum\":1,\"roadnet\":{\"crossId\":\"13NG40B5SK0\",\"laneId\":\"13NI00B5RM013NID0B5RM0010011\",\"rid\":\"13NI00B5RM013NID0B5RM00\",\"segmentId\":\"13NI00B5RM013NID0B5RM00100\"}},{\"id\":692528,\"licenseColor\":0,\"picLicense\":\"鲁A17N7G\",\"originalColor\":9,\"originalType\":1,\"longitude\":117.0946719,\"latitude\":36.6449299,\"speed\":28.88,\"altitude\":0.0,\"courseAngle\":83.0,\"baseLocation\":0,\"waitingTime\":0,\"stopNum\":0,\"roadnet\":{\"crossId\":\"13NG40B5SK0\",\"laneId\":\"null\",\"rid\":\"null\",\"segmentId\":\"null\"}},{\"id\":692478,\"licenseColor\":0,\"picLicense\":\"默A00000\",\"originalColor\":0,\"originalType\":1,\"longitude\":117.0948739,\"latitude\":36.6448864,\"speed\":33.59,\"altitude\":0.0,\"courseAngle\":88.0,\"baseLocation\":0,\"waitingTime\":0,\"stopNum\":0,\"roadnet\":{\"crossId\":\"13NG40B5SK0\",\"laneId\":\"null\",\"rid\":\"null\",\"segmentId\":\"null\"}},{\"id\":692702,\"licenseColor\":9,\"picLicense\":null,\"originalColor\":0,\"originalType\":1,\"longitude\":117.0947037,\"latitude\":36.6453683,\"speed\":37.37,\"altitude\":0.0,\"courseAngle\":4.0,\"baseLocation\":0,\"waitingTime\":0,\"stopNum\":0,\"roadnet\":{\"crossId\":\"13NG40B5SK0\",\"laneId\":\"13NI00B5RM013NG40B5SK0010011\",\"rid\":\"13NI00B5RM013NG40B5SK00\",\"segmentId\":\"13NI00B5RM013NG40B5SK00100\"}},{\"id\":692637,\"licenseColor\":0,\"picLicense\":\"默A00000\",\"originalColor\":0,\"originalType\":1,\"longitude\":117.08569779999999,\"latitude\":36.6422727,\"speed\":21.75,\"altitude\":0.0,\"courseAngle\":161.0,\"baseLocation\":0,\"waitingTime\":0,\"stopNum\":0,\"roadnet\":{\"crossId\":\"null\",\"laneId\":\"13NDG0B5RI013NF80B5QN0031011\",\"rid\":\"13NDG0B5RI013NF80B5QN00\",\"segmentId\":\"13NDG0B5RI013NF80B5QN00310\"}},{\"id\":692680,\"licenseColor\":9,\"picLicense\":null,\"originalColor\":0,\"originalType\":1,\"longitude\":117.08775929999999,\"latitude\":36.642967,\"speed\":29.81,\"altitude\":0.0,\"courseAngle\":55.0,\"baseLocation\":0,\"waitingTime\":0,\"stopNum\":0,\"roadnet\":{\"crossId\":\"null\",\"laneId\":\"13NF80B5QN013NGH0B5RC0024013\",\"rid\":\"13NF80B5QN013NGH0B5RC00\",\"segmentId\":\"13NF80B5QN013NGH0B5RC00240\"}},{\"id\":692490,\"licenseColor\":0,\"picLicense\":\"鲁A17AL0\",\"originalColor\":2,\"originalType\":1,\"longitude\":117.0862291,\"latitude\":36.6415836,\"speed\":22.65,\"altitude\":0.0,\"courseAngle\":135.0,\"baseLocation\":0,\"waitingTime\":16,\"stopNum\":1,\"roadnet\":{\"crossId\":\"null\",\"laneId\":\"13NF80B5QN013NDT0B5Q90021011\",\"rid\":\"13NF80B5QN013NDT0B5Q900\",\"segmentId\":\"13NF80B5QN013NDT0B5Q900210\"}},{\"id\":692559,\"licenseColor\":0,\"picLicense\":\"鲁AK7338\",\"originalColor\":0,\"originalType\":1,\"longitude\":117.09333509999999,\"latitude\":36.6448227,\"speed\":24.74,\"altitude\":0.0,\"courseAngle\":78.0,\"baseLocation\":0,\"waitingTime\":0,\"stopNum\":0,\"roadnet\":{\"crossId\":\"null\",\"laneId\":\"13NGH0B5RC013NI00B5RM0025011\",\"rid\":\"13NGH0B5RC013NI00B5RM00\",\"segmentId\":\"13NGH0B5RC013NI00B5RM00250\"}},{\"id\":692525,\"licenseColor\":0,\"picLicense\":\"鲁AP5926\",\"originalColor\":1,\"originalType\":1,\"longitude\":117.0898222,\"latitude\":36.6445928,\"speed\":19.84,\"altitude\":0.0,\"courseAngle\":347.0,\"baseLocation\":0,\"waitingTime\":30,\"stopNum\":1,\"roadnet\":{\"crossId\":\"null\",\"laneId\":\"13NGH0B5RC013NEH0B5RJ0020011\",\"rid\":\"13NGH0B5RC013NEH0B5RJ00\",\"segmentId\":\"13NGH0B5RC013NEH0B5RJ00200\"}},{\"id\":692668,\"licenseColor\":0,\"picLicense\":\"鲁AX337M\",\"originalColor\":0,\"originalType\":1,\"longitude\":117.086266,\"latitude\":36.6421235,\"speed\":31.79,\"altitude\":0.0,\"courseAngle\":46.0,\"baseLocation\":0,\"waitingTime\":0,\"stopNum\":0,\"roadnet\":{\"crossId\":\"13NF80B5QN0\",\"laneId\":\"13NF80B5QN013NGH0B5RC0010012\",\"rid\":\"13NF80B5QN013NGH0B5RC00\",\"segmentId\":\"13NF80B5QN013NGH0B5RC00100\"}}]" ;
ParserJsonArray parserJsonArray = new ParserJsonArray();
parserJsonArray.eval(json);
}
}
package com.wanji.indicators.util;
import com.wanji.indicators.constant.Constant;
import com.wanji.indicators.model.CarTrackModel;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
public class CommonUtil {
private static final Logger log = LoggerFactory.getLogger(CommonUtil.class);
public static boolean isInCrossing(CarTrackModel carTrackModel){
CarTrackModel.RoadNet roadNet = carTrackModel.getRoadnet();
String crossId = roadNet.getCrossId();
String rid = roadNet.getRid();
String laneId = roadNet.getLaneId();
String segmentId = roadNet.getSegmentId();
if (!Objects.equals("null",crossId) && Objects.equals("null",rid) && Objects.equals("null",laneId)) {
return true;
} else {
return false;
}
}
/**
* 过滤拥堵场景下的事故上报
* @param rid
* @param trackIds
* @return
*/
// public static int ridIsCongested(String rid, String trackIds, ConcurrentHashMap<String, EventCross> cache){
// int stopRidNum = 0;
// if(StringUtils.isNotBlank(rid)){
// for(EventCross e : cache.values()){
// if(rid.equals(e.getRid())){
// if(!trackIds.contains(String.valueOf(e.getTrackID())) && e.getAreaDist() < 13.0){
// stopRidNum++;
// }
// }
// }
// }
// return stopRidNum;
// }
/**
* 获取车道功能
* @param matchLaneName
* @return
*/
public static String getLaneFunc(String matchLaneName){
if(StringUtils.isBlank(matchLaneName)){
return Constant.STRAIGHT_LINE_CODE;
}
String[] s = matchLaneName.split(" ");
String laneFuncChn = "";
String laneFunc = "";
if(s.length == 3){
laneFuncChn = s[1];
}
for(String k : Constant.mapTurn.keySet()){
String v = Constant.mapTurn.get(k);
if(laneFuncChn.contains(v)){
laneFunc += k + Constant.COMMA;
}
}
if(StringUtils.isNotBlank(laneFunc)){
laneFunc = laneFunc.substring(0,laneFunc.lastIndexOf(Constant.COMMA));
}else{
laneFunc = Constant.STRAIGHT_LINE_CODE;;
}
return laneFunc;
}
/**
* 排序 -- 时间戳 -- 升序
* @param list
* @return
*/
// public static List<EventCross> getSortList(List<EventCross> list) {
// try {
// Collections.sort(list, new Comparator<EventCross>() {
// @Override
// public int compare(EventCross o1, EventCross o2) {
// long o1x = o1.getTime();
// long o2x = o2.getTime();
// if (o1x > o2x) {
// return 1;
// }
// if (o1x == o2x) {
// return 1;
// }
// return -1;
// }
// });
// return list;
// } catch (Exception e) {
// return list;
// }
// }
/**
* 加载配置项
*/
public String getWorkSpasePath() {
String path = "";
Properties props = System.getProperties();
String osName = props.getProperty("os.name");
String FLINK_WORKSPACE = System.getenv("FLINK_WORKSPACE_PATH");
log.info("当前操作系统: " + osName + " 环境变量配置: " + FLINK_WORKSPACE);
if (StringUtils.isNotBlank(osName) && osName.contains("Windows")) {
path = Constant.PATH_WINDOWS;
if (StringUtils.isNotBlank(FLINK_WORKSPACE)) {
path = FLINK_WORKSPACE + "\\";
log.info("读取 " + osName + " 外部环境变量配置: " + path);
}
} else {
path = Constant.PATH_LINUX;
if (StringUtils.isNotBlank(FLINK_WORKSPACE)) {
path = FLINK_WORKSPACE;
log.info("读取 " + osName + " 外部环境变量配置: " + path);
}
}
return path;
}
}
......@@ -7,10 +7,12 @@ import com.vividsolutions.jts.io.WKTReader;
import com.vividsolutions.jts.linearref.LengthLocationMap;
import com.vividsolutions.jts.linearref.LinearLocation;
import com.vividsolutions.jts.linearref.LocationIndexedLine;
import com.vividsolutions.jts.operation.buffer.BufferOp;
import com.vividsolutions.jts.operation.buffer.BufferParameters;
import com.vividsolutions.jts.operation.buffer.OffsetCurveBuilder;
import com.vividsolutions.jts.operation.distance.DistanceOp;
import com.vividsolutions.jts.operation.linemerge.LineMerger;
import com.vividsolutions.jts.util.GeometricShapeFactory;
import org.apache.commons.lang.StringUtils;
import java.math.BigDecimal;
......@@ -27,9 +29,32 @@ public class GeomsConvertUtil {
// 地球的极半径是6356725米
public final static double Rj = 6356725;
/**
* 按距离缓冲偏移坐标
* @param xys 坐标集合,格式:x,y;x1,y1;...,xn,yn
* @param distance 偏移的距离,单位:米,正数为向左平移,负数时为向右偏移
* @return 返回偏移后的坐标集合 格式:x,y;x1,y1;...,xn,yn
*/
public static String offsetCureLine(String xys,double distance) {
String offsetxy = "";
/*============定义缓冲样式========================*/
BufferParameters bufferParameters = new BufferParameters();
bufferParameters.setEndCapStyle(BufferParameters.CAP_FLAT);
bufferParameters.setJoinStyle(BufferParameters.JOIN_MITRE);
bufferParameters.setQuadrantSegments(18);
//米转换为度单位
distance = meterToDu(distance);
LineString lineString = GeomsConvertUtil.getLineString(xys);
BufferOp bufferOp = new BufferOp(lineString,bufferParameters);
Geometry offsetGeometry = bufferOp.getResultGeometry(distance);
try {
offsetxy = formatWkt(offsetGeometry.toText());
} catch (ParseException e) {
e.printStackTrace();
}
return offsetxy;
}
/**
* 按距离缓冲偏移坐标
......@@ -55,7 +80,7 @@ public class GeomsConvertUtil {
i++;
}
//米转换为度单位
distance *= 0.00001141 ;
distance = meterToDu(distance);
/*===============调用偏移方法进行偏移======================*/
OffsetCurveBuilder offsetCurveBuilder = new OffsetCurveBuilder(geometryFactory.getPrecisionModel(), bufferParameters);
Coordinate[] outPts = offsetCurveBuilder.getOffsetCurve(inputPts, distance);
......@@ -980,10 +1005,17 @@ public class GeomsConvertUtil {
return lineList;
}
public static void main(String[] args) throws Exception {
String wkt = "121.424661,31.39226;121.424881,31.39151;121.427819,31.381745;121.427953,31.381296;121.428082,31.380837;121.429196,31.376526;121.429994,31.373874;121.430299,31.372705;121.430537,31.371323;121.430723,31.370427;121.430914,31.369555;121.431103,31.368691;121.43127,31.367942;121.432941,31.362217;121.433261,31.360896;121.433515,31.35981;121.433691,31.358866;121.43398,31.35595;121.434063,31.355082;121.434143,31.354235;121.434701,31.348262;121.434975,31.347014;121.435106,31.346518;121.435187,31.346232;121.435625,31.345065;121.435902,31.344285;121.436606,31.342377;121.437375,31.340518;121.437711,31.339703;121.438044,31.338884;121.439232,31.33604;121.441546,31.33113;121.443878,31.326024;121.445757,31.321816;121.446752,31.31966;121.447063,31.318936;121.447369,31.318237;121.447905,31.316858;121.448035,31.316267;121.448187,31.315546;121.448293,31.314782;121.448497,31.313164;121.448623,31.310281;121.448696,31.307901;121.44866,31.307303;121.448642,31.306604;121.448625,31.305913;121.448931,31.300276;121.448984,31.299198;121.449126,31.298117;121.449373,31.296527;121.450076,31.293463;121.450251,31.292556;121.450429,31.291631;121.450841,31.289895;121.451269,31.287919;121.451429,31.286805;121.451543,31.285801;121.451693,31.284324;121.451924,31.28113;121.452023,31.279895;121.452124,31.278661;121.45231,31.277347;121.452461,31.276862;121.452637,31.276333;121.453007,31.275443;121.453265,31.274885;121.454004,31.273619;121.455329,31.271675;121.45583,31.27095;121.457568,31.268372;121.457939,31.267754;121.458115,31.267362;121.458265,31.26697;121.458421,31.265833;121.458557,31.263704;121.45866,31.26213;121.458817,31.260169;121.45895,31.259749;121.459204,31.258891;121.45946,31.258028;121.459485,31.257836;121.459485,31.257535;121.459496,31.256501;121.459479,31.255648;121.459418,31.254958;121.459025,31.252636;121.458995,31.252406;121.459004,31.252209;121.459112,31.250582;121.459083,31.250372;121.459011,31.250177;121.458846,31.25002;121.458636,31.249863;121.457204,31.249166;121.456868,31.248956;121.456573,31.248734;121.456389,31.248532;121.456215,31.248302;121.456047,31.247995;121.455684,31.247255;121.455313,31.2465;121.455125,31.246055;121.455018,31.245642;121.454982,31.245213;121.454998,31.244865;121.455065,31.244482;121.455181,31.244115;121.455346,31.243768;121.455529,31.243495;121.455743,31.243257;121.456017,31.242991;121.456234,31.242817;121.456465,31.242656;121.456712,31.242519;121.456953,31.242422;121.457267,31.242317;121.457648,31.242207;121.458699,31.241883;121.459971,31.241503;121.460583,31.241306;121.461344,31.24104;121.467182,31.23874;121.468151,31.238373;121.469041,31.238051;121.470426,31.237687;121.471569,31.237297;121.471853,31.237137;121.472116,31.236953;121.472481,31.236665;121.472974,31.236165;121.474106,31.234365;121.475137,31.232781;121.476134,31.231231;121.477547,31.22947;121.478086,31.228782;121.478159,31.228679;121.478189,31.228622;121.478233,31.22853;121.478277,31.228423;121.478386,31.228174;121.47843,31.227951;121.478461,31.227758;121.478468,31.227702;121.478473,31.22761;121.478472,31.22719;121.478448,31.226138;121.478445,31.225997;121.478438,31.225904;121.478417,31.225777;121.478378,31.22561;121.478332,31.225509;121.478246,31.225362;121.478035,31.225136;121.47761,31.224797;121.477185,31.224532;121.476407,31.224124;121.475127,31.223526;121.474212,31.223128;121.473306,31.222745;121.472383,31.222356;121.466695,31.22004;121.461164,31.217746;121.459957,31.217231;121.458745,31.216717;121.452162,31.213851;121.451048,31.213382;121.44972,31.212813;121.449563,31.212682;121.449412,31.212538;121.449314,31.212327;121.449314,31.212087;121.449296,31.211233;121.449211,31.210127;121.448814,31.208214;121.448792,31.208145;121.448652,31.207754;121.448576,31.207569;121.448494,31.207395;121.448466,31.207353;121.447669,31.206248;121.446883,31.205164;121.446424,31.204528;121.445965,31.203891;121.444296,31.201692;121.443138,31.200113;121.442022,31.198663;121.440277,31.196306;121.439249,31.194984;121.439126,31.194794;121.439068,31.194684;121.439012,31.194564;121.438969,31.194472;121.438133,31.191698;121.437404,31.189259;121.437235,31.188728;121.437119,31.188241;121.436961,31.187457;121.436745,31.186035;121.436528,31.184209;121.436272,31.182001;121.436151,31.180969;121.435985,31.179869;121.435917,31.179221;121.435513,31.175943;121.435218,31.173487;121.435111,31.17245;121.435031,31.171169;121.434848,31.169209;121.434702,31.168228;121.434551,31.167266;121.434476,31.166688;121.43411,31.163133;121.434067,31.162858;121.434014,31.162583;121.433201,31.159207;121.432658,31.157705;121.432278,31.157017;121.431802,31.156247;121.430796,31.155095;121.430041,31.154579;121.429217,31.154016;121.428206,31.15342;121.424098,31.151061;121.420987,31.148834;121.417147,31.145353;121.416352,31.144585;121.415073,31.143098;121.414604,31.142675;121.414107,31.142217;121.413622,31.141771;121.409971,31.138218;121.405856,31.133814;121.403605,31.131565;121.40291,31.1309;121.402241,31.130274;121.401049,31.129156;121.400066,31.128214;121.398684,31.126855;121.396102,31.124412;121.395084,31.123459;121.3947,31.123076;121.394223,31.122539;121.393845,31.122059;121.393524,31.121616;121.39302,31.120899;121.392492,31.120155;121.39125,31.118396;121.390298,31.117133;121.38802,31.114151;121.387549,31.113551;121.38586,31.11171;121.385373,31.111152";
/* LineString ls = GeomsConvertUtil.getLineString(wkt);
System.out.println(offsetCureLine(wkt,1));
System.out.println(offsetCure(wkt,1));
Point point = createPoint("121.424661,31.39226");
Geometry geometry = point.buffer(meterToDu(10));
System.out.println(formatWkt(geometry.toText()));
/* LineString ls = GeomsConvertUtil.getLineString(wkt);
LocationIndexedLine lil = new LocationIndexedLine(ls);
LinearLocation start = lil.indexOf(new Coordinate(8, 5));
......@@ -991,11 +1023,11 @@ public class GeomsConvertUtil {
Geometry result = lil.extractLine(start, end);
System.out.println(result.toText());*/
Geometry result = GeomsConvertUtil.getSubLineString(wkt, new Coordinate(121.385373,31.111152), new Coordinate(121.393020,31.120899));
System.out.println(result.toText());
Geometry result1 = GeomsConvertUtil.getSubLineString(wkt, new Coordinate(121.393025,31.120899), new Coordinate(121.385373,31.111152));
System.out.println(result1.toText());
// Geometry result = GeomsConvertUtil.getSubLineString(wkt, new Coordinate(121.385373,31.111152), new Coordinate(121.393020,31.120899));
// System.out.println(result.toText());
//
// Geometry result1 = GeomsConvertUtil.getSubLineString(wkt, new Coordinate(121.393025,31.120899), new Coordinate(121.385373,31.111152));
// System.out.println(result1.toText());
}
}
......@@ -240,9 +240,11 @@ public class PtInPolyUtil {
.getY() - B.getY()) <= 0.0D && (intersection
.getY() - C.getY()) * (intersection
.getY() - D.getY()) <= 0.0D) {
if ((A.getX() == C.getX() && A.getY() == C.getY()) || (A.getX() == D.getX() && A.getY() == D.getY()) || (B
.getX() == C.getX() && B.getY() == C.getY()) || (B.getX() == D.getX() && B.getY() == D.getY()))
return 2;
//相交
if ((A.getX() == C.getX() && A.getY() == C.getY()) || (A.getX() == D.getX() && A.getY() == D.getY()) || (B
.getX() == C.getX() && B.getY() == C.getY()) || (B.getX() == D.getX() && B.getY() == D.getY())) {
return 2;
}
return 1;
}
return -1;
......
package com.wanji.indicators.util;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeanUtils;
import java.io.*;
import java.net.*;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.*;
import java.util.zip.Deflater;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
import java.util.zip.Inflater;
/**
* 工具帮助类
*
* @author shiguang.zhou
*
*/
public class Tools {
private static Log logger = LogFactory.getLog(Tools.class);
public static SerializerFeature[] fastJsonFeatures = {SerializerFeature.WriteNullNumberAsZero, SerializerFeature.WriteNullStringAsEmpty, SerializerFeature.WriteMapNullValue,SerializerFeature.DisableCircularReferenceDetect};
static Random random = new Random();
public static String getMapValue(String key,Map<String, Object> map) {
if (map.containsKey(key))
return map.get(key).toString();
return null;
}
/**
* 获取随机数
* @param max
* @param min
* @return
*/
public static int getRandomValue(int max,int min){
Random r = new Random();
int num =r.nextInt(max+1-min)+min;
return num;
}
public static Object mapToObject(Map<String, Object> map, Class<?> beanClass) throws Exception {
if (map == null)
return null;
Object obj = beanClass.newInstance();
BeanUtils.copyProperties(map,obj);
return obj;
}
public static char int2char(int n){
return (char)(n+48);
}
/**
* fastjson 空数据处理
* @param jsonObj
* @return
*/
public static String fastJsonNullFormat(JSONObject jsonObj){
return jsonObj.toJSONString(jsonObj, fastJsonFeatures);
}
/**
* 反射生成实例
*
* @param className
* @return
*/
public static Object getClassInstance(String className) {
if (className == null || className.trim().length() == 0) {
return null;
}
Class<?> objClass = null;
Object obj = null;
try {
objClass = Class.forName(className);
obj = objClass.newInstance();
} catch (Exception e) {
logger.error("", e);
}
return obj;
}
/**
* hashmap 按值排序 升序排列
*
* @param map
* @param sortType 1升序 2降序
* @return
*/
public static <K, V extends Comparable<? super V>> Map<K, V> sortByValue(
Map<K, V> map,int sortType) {
List<Map.Entry<K, V>> list = new LinkedList<Map.Entry<K, V>>(
map.entrySet());
Collections.sort(list, new Comparator<Map.Entry<K, V>>() {
public int compare(Map.Entry<K, V> o1, Map.Entry<K, V> o2) {
if (o1.getValue() == null || o2.getValue() == null)
return 0;
if (sortType==2) {
if ((o1.getValue()).compareTo(o2.getValue()) < 0) {
return 1;
} else if ((o1.getValue()).compareTo(o2.getValue()) > 0) {
return -1;
} else {
return 0;
}
}else {
if ((o1.getValue()).compareTo(o2.getValue()) < 0) {
return -1;
} else if ((o1.getValue()).compareTo(o2.getValue()) > 0) {
return 1;
} else {
return 0;
}
}
}
});
Map<K, V> result = new LinkedHashMap<K, V>();
for (Map.Entry<K, V> entry : list) {
result.put(entry.getKey(), entry.getValue());
}
return result;
}
/**
* 把坐标度转换成毫秒
*
* @param xy
* 坐标点,经度或纬度
* @return 毫秒字符串
* @author shiguang.zhou
*/
public static String Du2Second(String xy) {
double DDD = Double.parseDouble(xy);
double ms = DDD * 60 * 60 * 1000;
return (int) ms + "";
}
/**
* 16进制的字符转换成 byte数组
*
* @param s
* 为16进制串,每个字节16进制为2位,s合法长度为偶数
* @return 字节数组byte[]
* @author shiguang.zhou
*/
public static byte[] fromHexString(String s) {
int stringLength = s.length();
if ((stringLength & 0x1) != 0) {
throw new IllegalArgumentException(
"fromHexString requires an even number of hex characters");
}
byte[] b = new byte[stringLength / 2];
for (int i = 0, j = 0; i < stringLength; i += 2, j++) {
int high = charToNibble(s.charAt(i));
int low = charToNibble(s.charAt(i + 1));
b[j] = (byte) ((high << 4) | low);
}
return b;
}
private static int charToNibble(char c) {
if ('0' <= c && c <= '9') {
return c - '0';
} else if ('a' <= c && c <= 'f') {
return c - 'a' + 0xa;
} else if ('A' <= c && c <= 'F') {
return c - 'A' + 0xa;
} else {
throw new IllegalArgumentException("Invalid hex character: "
+ c);
}
}
/**
* 把byte数组转换成16进制字符
*
* @param bs
* 待转换的数组
* @return 16进制字符串
* @author shiguang.zhou
*/
public static String bytesToHexString(byte[] bs) {
String s = "";
for (int i = 0; i < bs.length; i++) {
String tmp = Integer.toHexString(bs[i] & 0xff);
if (tmp.length() < 2) {
tmp = "0" + tmp;
}
s = s + tmp;
}
return s;
}
/**
* 把byte转换成16进制字符
*
* @param bs
* 待转换的数组
* @return 16进制字符串
* @author shiguang.zhou
*/
public static String byteToHexString(byte bs) {
String s = Integer.toHexString(bs & 0xff);
if (s.length() < 2) {
s = "0" + s;
}
return s;
}
/**
* 将低自己在前转换为低字节在后数组 或将高字节在前转换为高字节在后数组
*
* @param littleByte
* 待转换字节数组
* @return 转换后的字节数组
*/
public static byte[] convertBytePos(byte[] littleByte) {
byte[] ret = new byte[littleByte.length];
for (int i = 0; i < littleByte.length; i++) {
ret[i] = littleByte[littleByte.length - i - 1];
}
return ret;
}
/**
* bytes to int 通过移位实现
*
* @param decBytes
* @return int
* @author shiguang.zhou
* @modify 将遍历次数调整为数组长度 2014.03.25 wu.wei
*/
public static int byte2Int(byte[] decBytes) {
int value = 0;
for (int i = 0; i < decBytes.length; i++) {
int shift = (decBytes.length - 1 - i) * 8;
value += (decBytes[i] & 0x000000FF) << shift;
}
return value;
}
/**
* bytes to long
*
* @param
* @return long
* @author shiguang.zhou
*/
public static long byte2Long(byte[] b) {
long s = 0;
long s0 = b[0] & 0xff;// 最低位
long s1 = b[1] & 0xff;
long s2 = b[2] & 0xff;
long s3 = b[3] & 0xff;
long s4 = b[4] & 0xff;// 最低位
long s5 = b[5] & 0xff;
long s6 = b[6] & 0xff;
long s7 = b[7] & 0xff;
// s0不变
s1 <<= 8;
s2 <<= 16;
s3 <<= 24;
s4 <<= 8 * 4;
s5 <<= 8 * 5;
s6 <<= 8 * 6;
s7 <<= 8 * 7;
s = s0 | s1 | s2 | s3 | s4 | s5 | s6 | s7;
return s;
}
/**
* 把整型转换成指定长度的十六进制的字符
*
* @param num
* 整数值
* @param ws
* 转换后的长度
* @return 转换后的16进制字符串
* @author shiguang.zhou
*/
public static String int2Hexstring(int num, int ws) {
String intHex = Integer.toHexString(num);
while (intHex.length() < ws) {
intHex = "0" + intHex;
}
return intHex;
}
/**
* 把整型字符串值转换为指定长度的16进制
*
* @param num
* 待转换的整型串
* @param n
* 转换后的长度
* @return 转换后的16进制字符串
* @author shiguang.zhou
*/
public static String convertToHex(String num, int n) {
String temp = "";
long i = Long.parseLong(num);
String hex = Long.toHexString(i);// .toUpperCase();
if (hex.length() > n) {
int off = 0;
while (off < n) {
temp = temp + "F";
off++;
}
return temp;
} else if (hex.length() < n) {
while (hex.length() < n) {
hex = "0" + hex;
}
temp = hex;
} else {
temp = hex;
}
return temp;
}
/**
* 数据ZLIB压缩
*
* @param data
* 待压缩数据
* @return 压缩后的数据
*/
public static byte[] compressZLib(byte[] data) {
byte[] output = new byte[0];
Deflater compresser = new Deflater(Deflater.BEST_COMPRESSION);
compresser.reset();
compresser.setInput(data);
compresser.finish();
ByteArrayOutputStream bos = new ByteArrayOutputStream(data.length);
try {
byte[] buf = new byte[1024];
while (!compresser.finished()) {
int i = compresser.deflate(buf);
bos.write(buf, 0, i);
}
output = bos.toByteArray();
} catch (Exception e) {
output = data;
logger.error("", e);
} finally {
try {
bos.close();
} catch (IOException e) {
logger.error("", e);
}
}
compresser.end();
return output;
}
/**
* ZLIB数据解压
*
* @param data
* 待解压数据
* @return 解压后的数据
*/
public static byte[] decompressByteData(byte[] data) {
byte[] output = new byte[0];
Inflater decompresser = new Inflater();
decompresser.reset();
decompresser.setInput(data);
ByteArrayOutputStream o = new ByteArrayOutputStream(data.length);
try {
byte[] buf = new byte[1024];
while (!decompresser.finished()) {
int i = decompresser.inflate(buf);
o.write(buf, 0, i);
}
output = o.toByteArray();
} catch (Exception e) {
output = data;
logger.error("", e);
} finally {
try {
o.close();
} catch (IOException e) {
logger.error("", e);
}
}
decompresser.end();
return output;
}
/**
* BCD码转为10进制串(阿拉伯数据)
*
* @param bytes
* BCD码字节数组
* @return 10进制串
*/
public static String bcd2Str(byte[] bytes) {
StringBuilder temp = new StringBuilder(bytes.length * 2);
for (int i = 0; i < bytes.length; i++) {
temp.append((byte) ((bytes[i] & 0xf0) >>> 4));
temp.append((byte) (bytes[i] & 0x0f));
}
return temp.toString().substring(0, 1).equalsIgnoreCase("0") ? temp
.toString().substring(1) : temp.toString();
}
/**
* 10进制串转为BCD码
*
* @param asc
* 10进制串
* @return BCD码字节数组
*/
public static byte[] str2Bcd(String asc) {
int len = asc.length();
int mod = len % 2;
if (mod != 0) {
asc = "0" + asc;
len = asc.length();
}
byte abt[] = new byte[len];
if (len >= 2) {
len = len / 2;
}
byte bbt[] = new byte[len];
abt = asc.getBytes();
int j, k;
for (int p = 0; p < asc.length() / 2; p++) {
if ((abt[2 * p] >= '0') && (abt[2 * p] <= '9')) {
j = abt[2 * p] - '0';
} else if ((abt[2 * p] >= 'a') && (abt[2 * p] <= 'z')) {
j = abt[2 * p] - 'a' + 0x0a;
} else {
j = abt[2 * p] - 'A' + 0x0a;
}
if ((abt[2 * p + 1] >= '0') && (abt[2 * p + 1] <= '9')) {
k = abt[2 * p + 1] - '0';
} else if ((abt[2 * p + 1] >= 'a') && (abt[2 * p + 1] <= 'z')) {
k = abt[2 * p + 1] - 'a' + 0x0a;
} else {
k = abt[2 * p + 1] - 'A' + 0x0a;
}
int a = (j << 4) + k;
byte b = (byte) a;
bbt[p] = b;
}
return bbt;
}
// jiangkeping
public static JSONArray sortJSONArray(JSONArray jsonArr, String sortKey){
JSONObject jObject = null;
for(int i = 0;i<jsonArr.size();i++){
long l = Long.parseLong(jsonArr.getJSONObject(i).get(sortKey).toString());
for(int j = i+1; j<jsonArr.size();j++){
long nl = Long.parseLong(jsonArr.getJSONObject(j).get(sortKey).toString());
if(l>nl){
jObject = jsonArr.getJSONObject(j);
jsonArr.set(j, jsonArr.getJSONObject(i));
jsonArr.set(i, jObject);
}
}
}
return jsonArr;
}
/**
*
* @param ja json数组
* @param field 要排序的key
* @param isAsc 是否升序
*/
// private static void sort(JSONArray ja,final String field, boolean isAsc){
// Collections.sort(ja, new Comparator<JSONObject>() {
// @Override
// public int compare(JSONObject o1, JSONObject o2) {
// Object f1 = o1.get(field);
// Object f2 = o2.get(field);
// if(f1 instanceof Number && f2 instanceof Number){
// return ((Number)f1).intValue() - ((Number)f2).intValue();
// }else{
// return f1.toString().compareTo(f2.toString());
// }
// }
// });
// if(!isAsc){
// Collections.reverse(ja);
// }
// }
//
/**
* 把度转换成16进制毫秒
*
* @param xy
* 坐标点经度或纬度
* @return 转换后的16进制毫秒值
* @author shiguang.zhou
*/
public static String Du2Mills(String xy) {
double DDD = Double.parseDouble(xy);
int ms = (int) (DDD * 60 * 60 * 1000);
String hex = Integer.toHexString(ms);
return hex.toUpperCase();
}
/**
* 获取一个n位随机数值
*
* @param n
* 随机数位数
*
* @return n位随机数
*
* @author shiguang.zhou
*/
public static String getRandomNum(int n) {
String seed = "0123456789";
byte chs[] = seed.getBytes();
byte bs[] = new byte[n];
int length = chs.length;
for (int i = 0; i < n; i++) {
bs[i] = chs[random.nextInt(length)];
}
return new String(bs);
}
/**
* 数据包异或校验值
*
* @param b
* 待校验内容
* @return 校验值
*
* @author shiguang.zhou
*/
public static byte checkData(byte[] b) {
byte result = b[0];
int i = 1;
while (i < b.length) {
result ^= b[i];
i++;
}
return result;
}
/**
* 格式化double数值
*
* @param df
* 待格式化数据
* @param maxfracDigit
* 允许保留最大小数点
* @param minfracDigit
* 允许保留最小小数点
* @return 格式化后的数据
*
* @author shiguang.zhou
*/
public static String getNumberFormatString(double df, int maxfracDigit,
int minfracDigit) {
String ret = "";
NumberFormat nf = NumberFormat.getInstance();
nf.setMaximumFractionDigits(maxfracDigit);
nf.setMinimumFractionDigits(minfracDigit);
ret = nf.format(df).replaceAll("\\,", "");
return ret;
}
/**
*
* 判断一个字节每个bit位的数值
*
* @param data
* 高位在前,地位在后的字节内容
* @param pos
* 字节的第几位
* @return 字节bit位值(为0或1)
* @author shiguang.zhou
* @modify 调整compare类型,使之可以判断4字节整形数字
*/
public static int getByteBit(int data, int pos) {
int bitData = 0;
int compare = (int) Math.pow(2, pos);
if ((data & compare) == compare) {
bitData = 1;
}
return bitData;
}
/**
* 负数补码获取到原码
*
* @param hexString
* 16进制数
* @return 原码
*
* @author shiguang.zhou
*/
public static int getValueFromCompCode(String hexString) {
int ret = 0;
int i = Integer.parseInt(hexString.substring(1), 16);
int j = Integer.parseInt("fffffff", 16);
int m = i ^ j;
if (hexString.charAt(0) == 'F') {// 负数
ret = -(m + 1);
}
return ret;
}
/**
* 16进制毫秒转换为度
*
* @param mills
* 16进制毫秒
* @return 浮点度值
*
* @author shiguang.zhou
*/
public static String fromMs2XY(String mills) {
String ret = "";
try {
double ms = Integer.parseInt(mills, 16);
double ds = ms / 1000 / 60 / 60;
DecimalFormat format = new DecimalFormat("0.000000");
format.setMaximumFractionDigits(6);
ret = format.format(ds);
} catch (Exception e) {
ret = "0";
}
return ret;
}
/**
* 把节转换成公里
*
* @param knot
* 节
* @return 公里
*
* @author shiguang.zhou
*/
public static String formatKnotToKm(String knot) {
if (knot == null || knot.trim().length() <= 0) {
return "0";
}
String ret = "";
double speed = 0;
if (knot != null) {
try {
speed = Double.parseDouble(knot);
} catch (NumberFormatException ex) {
logger.error("", ex);
}
speed = speed * 1.852;
}
ret = "" + speed;
if (ret.length() > 4) {
ret = ret.substring(0, 4);
}
return ret;
}
/**
* 把公里转换成节
*
* @param km
* 公里
* @return 节
*
* @author shiguang.zhou
*/
public static String formatKmToKnot(String km) {
String knot = "";
double dSpeed = Double.parseDouble(km);
double hSpeed = dSpeed / 1.852;
int iSpeed = (int) hSpeed;
knot = "" + iSpeed;
return knot;
}
/**
* 对字节数组进行字节累加和校验的16进制串
*
* @param bcont
* 待校验的内容
* @return 校验和16进制字符
*
*/
public static String getVerfyCode(byte[] bcont) {
String ret = "";
byte[] br = bcont;
int sum = 0;
for (int i = 0; i < br.length; i++) {
sum += br[i] & 0xFF;
}
ret = Integer.toHexString(sum);
return ret;
}
public static byte[] double2Hexstring(double num, int ws) {
double n = num * 3600000;
String douHex = Integer.toHexString((int) n);
while (douHex.length() < ws) {
douHex = "0" + douHex;
}
return fromHexString(douHex);
}
public static String HexToBinary(String hexString) {
long l = Long.parseLong(hexString, 16);
String binaryString = Long.toBinaryString(l);
int shouldBinaryLen = hexString.length() * 4;
StringBuilder addZero = new StringBuilder();
int addZeroNum = shouldBinaryLen - binaryString.length();
for (int i = 1; i <= addZeroNum; i++) {
addZero.append("0");
}
return addZero.toString() + binaryString;
}
/**
* 十进制转二进制 IntToBinary 方法
*
* @param
* @return String
*/
public static String IntToBinary(int intNum) {
String binaryString = Integer.toBinaryString(intNum);
int shouldBinaryLen = 8;// byte 八位
StringBuilder addZero = new StringBuilder();
int addZeroNum = shouldBinaryLen - binaryString.length();
for (int i = 1; i <= addZeroNum; i++) {
addZero.append("0");
}
return addZero.toString() + binaryString;
}
/**
* 修改指定二进制位置数字 IntToBinary 方法
*
* @param
* @return String
*/
public static String changeBinary(String binary, int pos, int value) {
if (binary == null || binary.length() < 8 || binary.length() < pos)
return binary;
pos = binary.length() - pos - 1;
String start = binary.substring(0, pos);
String end = binary.substring(pos + 1);
return start + value + end;
}
/**
* 把度分格式为DDMMmmmmm的经度转换成度
*
* @param DDMMmmmmm
* 纬度
* @return 浮点经度字符串
* @author shiguang.zhou
*/
public static String formatYtoDu(String DDMMmmmmm) {
double xy = Double.parseDouble(DDMMmmmmm);
if (xy == 0) {
return "0";
}
String result = null;
double DDD = Double.parseDouble(DDMMmmmmm.substring(0, 2));
double MMmmmm = Double.parseDouble(DDMMmmmmm.substring(2,
DDMMmmmmm.length()));
MMmmmm = MMmmmm / 60;
NumberFormat format = NumberFormat.getNumberInstance();
format.setMaximumFractionDigits(6);
format.setMinimumFractionDigits(6);
result = format.format(DDD + MMmmmm).replaceAll(",", "");
return result;
}
/**
* 把格式为DDDMMmmmmm的度分经度转换成度
*
* @param DDDMMmmmmm
* 经度
* @return 浮点经度字符串
* @author shiguang.zhou
*/
public static String formatXtoDu(String DDDMMmmmmm) {
double xy = Double.parseDouble(DDDMMmmmmm);
if (xy == 0) {
return "0";
}
String result = null;
double DDD = Double.parseDouble(DDDMMmmmmm.substring(0, 3));
double MMmmmm = Double.parseDouble(DDDMMmmmmm.substring(3,
DDDMMmmmmm.length()));
MMmmmm = MMmmmm / 60;
NumberFormat format = NumberFormat.getNumberInstance();
format.setMaximumFractionDigits(6);
format.setMinimumFractionDigits(6);
result = format.format(DDD + MMmmmm).replaceAll(",", "");
return result;
}
/**
* 字符串前补0
*
* @param str
* 待补0字符串
* @param i
* 补0的个数
* @return 补0后的字符串
*
*/
public static String fillZeroFront(String str, int i) {
while (str.length() < i) {
str = "0" + str;
}
return str;
}
/**
* 字符串后补0
*
* @param str
* 待补0字符串
* @param i
* 补0的个数
* @return 补0后的字符串
*
*/
public static String fillZeroBack(String str, int i) {
while (str.length() < i) {
str = str + "0";
}
return str;
}
/**
* 生成随即密码,由数字、大小写字母随机组成
*
* @param pwd_len
* 生成的密码的总长度
* @return 密码的字符串
*/
public static String getRandomString(int pwd_len) {
// 35是因为数组是从0开始的,26个字母+10个数字
final int maxNum = 48;
int i; // 生成的随机数
int count = 0; // 生成的密码的长度
char[] str = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k',
'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8',
'9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
'X', 'Y', 'Z' };
StringBuilder pwd = new StringBuilder("");
while (count < pwd_len) {
// 生成随机数,取绝对值,防止生成负数,
i = Math.abs(random.nextInt(maxNum)); // 生成的数最大为36-1
if (i >= 0 && i < str.length) {
pwd.append(str[i]);
count++;
}
}
return pwd.toString();
}
final static int BUFFER_SIZE = 4096;
/**
* 将InputStream转换成某种字符编码的String
*
* @param in
* @param encoding
* @return
* @throws Exception
*/
public static String InputStreamTOString(InputStream in, String encoding)
throws Exception {
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
byte[] data = new byte[BUFFER_SIZE];
int count = -1;
while ((count = in.read(data, 0, BUFFER_SIZE)) != -1)
outStream.write(data, 0, count);
data = null;
return new String(outStream.toByteArray(), encoding); // "ISO-8859-1"
}
/**
* telnet目标主机ip和端口,可连接返回true,无连接返回false
*
* @param ip
* @param port
* @return
*/
public static boolean telnet(String ip, int port) {
boolean isAlive = false;
Socket socket = null;
try {
socket = new Socket(ip, port);
if (socket.isConnected()) {
isAlive = true;
socket.close();
} else {
isAlive = false;
}
} catch (SocketException e) {
isAlive = false;
} catch (IOException e) {
isAlive = false;
} finally {
try {
if(socket != null) {
socket.close();
}
} catch (IOException e) {
}
}
return isAlive;
}
/**
* 判断是否是本地IP
*
* @return
*/
public static boolean isLocalIpAddres(String configIpPort) {
String gaterIpPort = new String();
int flag = 0;
try {
for (Enumeration<NetworkInterface> en = NetworkInterface
.getNetworkInterfaces(); en.hasMoreElements();) {
NetworkInterface intf = en.nextElement();
for (Enumeration<InetAddress> enumIpAddr = intf
.getInetAddresses(); enumIpAddr.hasMoreElements();) {
InetAddress inetAddress = enumIpAddr.nextElement();
if (!inetAddress.isLoopbackAddress()
&& !inetAddress.isLinkLocalAddress()
&& inetAddress.isSiteLocalAddress()) {
gaterIpPort = gaterIpPort
+ inetAddress.getHostAddress().toString() + ",";
flag++;
}
}
}
if (flag > 1) {
if (gaterIpPort.indexOf(configIpPort) < 0) {
return false;
}
}
} catch (Exception e) {
}
return true;
}
/**
* 转义
*
* @param str
* @return
*/
public static String convert(String str) {
if (null == str || str.equals("") || str.equals("null")) {
return "";
}
str = str.replace("&", "&amp;");
str = str.replace("$", "&dol;");
str = str.replace(",", "&cma;");
str = str.replace("(", "&lps;");
str = str.replace(")", "&rps;");
str = str.replace("#", "&num;");
return str;
}
/**
* 反转义
*
* @param str
* @return
*/
public static String disConvert(String str) {
if (null == str || str.equals("") || str.equals("null")) {
return "";
}
str = str.replace("&amp;", "&");
str = str.replace("&dol;", "$");
str = str.replace("&cma;", ",");
str = str.replace("&lps;", "(");
str = str.replace("&rps;", ")");
str = str.replace("&num;", "#");
return str;
}
public static int getHour(int flag) {
Calendar cal = Calendar.getInstance();
int i = cal.get(Calendar.HOUR_OF_DAY);
return i / flag;
}
/**
* 坐标点是否在中国境内
*
* @return false
*/
public static boolean isInChinaPoint(double tmpx, double tmpy) {
float maxX = 135.041666F;
float minX = 73.666666f;
float maxY = 53.55f;
float minY = 3.866666F;
if (tmpx > maxX || tmpx < minX || tmpy > maxY || tmpy < minY) {
return false;
}
return true;
}
/**
* 特殊字符转换
*
* @param str
* @return
*/
public static StringBuilder convert(StringBuilder str) {
if (null == str || str.toString().equals("")) {
return new StringBuilder();
}
while (str.indexOf("&num;") != -1)
str = str.replace(str.indexOf("&num;"), str.indexOf("&num;") + 5,
"#");
while (str.indexOf("&dol;") != -1)
str = str.replace(str.indexOf("&dol;"), str.indexOf("&dol;") + 5,
"$");
while (str.indexOf("&cma;") != -1)
str = str.replace(str.indexOf("&cma;"), str.indexOf("&cma;") + 5,
",");
while (str.indexOf("&lps;") != -1)
str = str.replace(str.indexOf("&lps;"), str.indexOf("&lps;") + 5,
"(");
while (str.indexOf("&rps;") != -1)
str = str.replace(str.indexOf("&rps;"), str.indexOf("&rps;") + 5,
")");
while (str.indexOf("&amp;") != -1)
str = str.replace(str.indexOf("&amp;"), str.indexOf("&amp;") + 5,
"#");
while (str.indexOf("/u007c") != -1)
str = str.replace(str.indexOf("/u007c"), str.indexOf("/u007c") + 6,
"|");
return str;
}
/**
* 判断当前操作是否Windows.
*
* @return true---是Windows操作系统
*/
public static boolean isWindowsOS() {
boolean isWindowsOS = false;
String osName = System.getProperty("os.name");
if (osName.toLowerCase().indexOf("windows") > -1) {
isWindowsOS = true;
}
return isWindowsOS;
}
/**
* MD5计算
*
* @param content
* @param charset
* @return
*/
public static String getMd5(String content, String charset) {
byte[] bcont = null;
if (charset == null || "".equals(charset)) {
return null;
}
try {
bcont = content.getBytes(charset);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("MD5签名过程中出现错误,指定的编码集不对,您目前指定的编码集是:"
+ charset);
}
String mysign = DigestUtils.md5Hex(bcont);
return mysign;
}
/**
* gzip压缩数据
*
* @param data
* @return
* @throws IOException
*/
public static byte[] gunzipData(byte[] data) throws IOException {
GZIPInputStream gin = null;
byte[] undata = null;
try{
gin = new GZIPInputStream(
new ByteArrayInputStream(data));
ByteArrayOutputStream tout = new ByteArrayOutputStream();
byte[] buffer = new byte[256];
int n = -1;
while ((n = gin.read(buffer)) >= 0) {
tout.write(buffer, 0, n);
}
undata = tout.toByteArray();
}catch(Exception e){
logger.error("", e);
}finally{
if (gin != null){
gin.close();
}
}
return undata;
}
/**
* gzip压缩数据
*
* @param data
* @return
* @throws IOException
*/
public static byte[] gzipData(byte[] data) throws IOException {
GZIPOutputStream gos = null;
byte[] gzdata = null;
try{
ByteArrayInputStream bais = new ByteArrayInputStream(data);
ByteArrayOutputStream gzipout = new ByteArrayOutputStream();
gos = new GZIPOutputStream(gzipout);
int len = 0;
byte[] buf = new byte[1024];
// 从in中读数据后经压缩流压缩后写入out流
while ((len = bais.read(buf)) != -1) {
gos.write(buf, 0, len);
}
gos.finish();
gos.flush();
gzdata = gzipout.toByteArray();
}catch(Exception e){
logger.error("", e);
}finally{
if (gos != null)
gos.close();
}
return gzdata;
}
// long类型转成byte数组
public static byte[] longToByte(long number) {
long temp = number;
byte[] b = new byte[8];
for (int i = 0; i < b.length; i++) {
b[i] = new Long(temp & 0xff).byteValue();// 将最低位保存在最低位
temp = temp >> 8; // 向右移8位
}
return b;
}
/**
* 路段唯一ID
*
* @param meshId
* @param roadId
* @return
*/
public static String getId(String meshId, String roadId) {
String ret = "";
if (meshId != null) {
ret = meshId + "_" + roadId;
}
return ret;
}
//全角转半角
public static String ToDBC(String input) {
if (StringUtils.isEmpty(input))
return null;
char c[] = input.toCharArray();
for (int i = 0; i < c.length; i++) {
if (c[i] == '\u3000') {
c[i] = ' ';
} else if (c[i] > '\uFF00' && c[i] < '\uFF5F') {
c[i] = (char) (c[i] - 65248);
}
}
String returnString = new String(c);
return returnString;
}
}
#kafka settings kafka1:9092,kafka2:9092,kafka3:9092 192.168.11.102:9092
#bootstrap.servers=10.102.1.182:9092
bootstrap.servers=192.168.2.103:9092
bootstrap.servers=10.102.1.182:9092
#bootstrap.servers=192.168.2.103:9092
#consumer-settings
consumer.topic=JNMatchResultMiniData
consumer.group.id=FlinkConsumerGroup-V56
consumer.group.id=FlinkConsumerGroup-V561
consumer.key-deserializer=org.apache.kafka.common.serialization.StringDeserializer
consumer.value-deserializer=org.apache.kafka.common.serialization.StringDeserializer
......@@ -13,8 +13,8 @@ producer.key-serializer=org.apache.kafka.common.serialization.StringSerializer
producer.value-serializer=org.apache.kafka.common.serialization.StringSerializer
#elasticsearch.server=10.102.1.182:9200
elasticsearch.server=192.168.2.103:9200
elasticsearch.server=10.102.1.182:9200
#elasticsearch.server=192.168.2.103:9200
elasticsearch.username=elastic
elasticsearch.password=Wanji300552
track_index_name=car-track-30s
......@@ -22,4 +22,7 @@ route_index_name=car-route-path
check.point.uri=file:///data/projects/savepoint
alarm.feishu.url=https://open.feishu.cn/open-apis/bot/v2/hook/0840f036-299e-4595-8a34-dea1c4ba6942
\ No newline at end of file
alarm.feishu.url=https://open.feishu.cn/open-apis/bot/v2/hook/0840f036-299e-4595-8a34-dea1c4ba6942
#·б
full.area.cross.list=13NI00B5RM0,13NGH0B5RC0,13NF80B5QN0
\ No newline at end of file
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://192.168.2.78:3306/t_roadnetwork_changsha?userUnicode=true&characterEncoding=utf-8
jdbc.driver=com.mysql.cj.jdbc.Driver
#jdbc.url=jdbc:mysql://10.102.1.182:3306/holo_roadnet_jn?userUnicode=true&characterEncoding=utf-8
jdbc.url=jdbc:mysql://37.12.182.29:3306/holo_roadnet?userUnicode=true&characterEncoding=utf-8
jdbc.username=root
jdbc.password=Wanji300552
......
......@@ -127,39 +127,49 @@
<!-- 查询路口进口车道、出口车道信息 -->
<select id="findCrossLaneInfo" parameterType="Map" resultType="map">
SELECT t.cross_id,t.road_id,t.rid,t.type,t.dir,count(*) lane_num,t.road_wkt,
GROUP_CONCAT(t.cut_point order by t.lane_id SEPARATOR '@') cut_point,
GROUP_CONCAT(t.turn order by t.lane_id) turn_list
SELECT t.cross_id,
t.lane_id,
t.rid,
t.type,
t.dir,
t.turn
FROM
( <!-- 进口方向RID车道 -->
select t1.id lane_id,substring_index(t1.wkt,';',-3) cut_point,t1.rid,t2.cross_id,t2.wkt road_wkt,t1.type,t1.dir,t2.road_id,t1.turn
from t_base_lane_info t1
JOIN (<!-- 取end_cross_id -->
select id,end_cross_id cross_id,in_dir as dir, 2 as type,wkt,if(road_id='#',concat_ws('',id,'#'),road_id) road_id
from t_base_rid_info
where 1=1
<if test="crossId !=null and crossId != ''">
and end_cross_id=#{crossId}
</if>
) t2 on t1.rid=t2.id and t1.type=t2.type
UNION
<!-- 出口方向RID车道 -->
select t1.id lane_id,substring_index(t1.wkt,';',3) cut_point,t1.rid,t2.cross_id,t2.wkt road_wkt,t1.type,t1.dir,t2.road_id,t1.turn
from t_base_lane_info t1
JOIN (<!-- 取start_cross_id -->
select id,start_cross_id cross_id,in_dir as dir, 3 as type,wkt,if(road_id='#',concat_ws('',id,'#'),road_id) road_id
from t_base_rid_info
where 1=1
<if test="crossId !=null and crossId != ''">
and start_cross_id=#{crossId}
</if>
) t2 on t1.rid=t2.id and t1.type=t2.type
select t1.id lane_id,substring_index(t1.wkt,';',-3) cut_point,t1.rid,t2.cross_id,t2.wkt road_wkt,t1.type,t1.dir,t2.road_id,t1.turn
from t_base_lane_info t1
JOIN (<!-- 取end_cross_id -->
select id,end_cross_id cross_id,in_dir as dir, 2 as type,wkt,if(road_id='#',concat_ws('',id,'#'),road_id) road_id
from t_base_rid_info
where 1=1
<if test="crossList != null and crossList.size>0">
and end_cross_id in
<foreach item="item" index="index" collection="crossList" separator="," open="(" close=")">
#{item}
</foreach>
</if>
) t2 on t1.rid=t2.id and t1.type=t2.type
UNION
<!-- 出口方向RID车道 -->
select t1.id lane_id,substring_index(t1.wkt,';',3) cut_point,t1.rid,t2.cross_id,t2.wkt road_wkt,t1.type,t1.dir,t2.road_id,t1.turn
from t_base_lane_info t1
JOIN (<!-- 取start_cross_id -->
select id,start_cross_id cross_id,in_dir as dir, 3 as type,wkt,if(road_id='#',concat_ws('',id,'#'),road_id) road_id
from t_base_rid_info
where 1=1
<if test="crossList != null and crossList.size>0">
and start_cross_id in
<foreach item="item" index="index" collection="crossList" separator="," open="(" close=")">
#{item}
</foreach>
</if>
) t2 on t1.rid=t2.id and t1.type=t2.type
) t
where 1=1
<if test="type !=null and type != ''">
and t.type = #{type}
</if>
GROUP BY t.cross_id,t.road_id,t.rid,t.type,t.dir
</select>
</mapper>
......@@ -30,6 +30,6 @@
</property>
</bean>
<mybatis:scan base-package="com.wanji.mapper" />
<mybatis:scan base-package="com.wanji.indicators.mapper" />
</beans>
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment