package cn.com.reformer.service.impl;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
import javax.annotation.Resource;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.geo.Box;
import org.springframework.data.geo.Circle;
import org.springframework.data.geo.Distance;
import org.springframework.data.geo.GeoResults;
import org.springframework.data.geo.Metrics;
import org.springframework.data.geo.Point;
import org.springframework.data.geo.Polygon;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.NearQuery;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;
import com.github.pagehelper.PageInfo;
import cn.com.reformer.common.util.DataUtil;
import cn.com.reformer.model.event.EventCondition;
import cn.com.reformer.model.vo.AnalysisVo;
@Service
public class MongoDBService {
@Resource
private MongoTemplate mongoTemplate;
//分页获取圆形数据
public PageInfo<AnalysisVo> getCircleEventPage(EventCondition condition) {
Query querys = this.getCommonQuery(condition);
NearQuery query = NearQuery.near(new Point(condition.getLongitude(), condition.getLatitude())).query(querys)
.maxDistance(new Distance(condition.getRadius(), Metrics.KILOMETERS)).limit(condition.getPageSize())
.skip((condition.getPageNum() - 1) * condition.getPageSize());
GeoResults<Object> geoResults = mongoTemplate.geoNear(query, Object.class, "resource");
PageInfo<AnalysisVo> pageInfo = new PageInfo<>(DataUtil.convert(geoResults.getContent(), condition));
pageInfo.setTotal(this.getCircleEventCount(condition));
pageInfo.setPageNum(condition.getPageNum());
pageInfo.setPageSize(condition.getPageSize());
return pageInfo;
}
// 获取圆形范围类数据
public List<AnalysisVo> getCircleEvent(EventCondition condition) {
Query querys = this.getCommonQuery(condition);
NearQuery query = NearQuery.near(new Point(condition.getLongitude(), condition.getLatitude())).query(querys)
.maxDistance(new Distance(condition.getRadius(), Metrics.KILOMETERS)).limit(condition.getPageSize())
.skip((condition.getPageNum() - 1) * condition.getPageSize());
GeoResults<Object> geoResults = mongoTemplate.geoNear(query, Object.class, "resource");
return DataUtil.convert(geoResults.getContent(),condition);
}
// 获取圆形范围类数据数量
public Long getCircleEventCount(EventCondition condition) {
Query querys = this.getCommonQuery(condition);
Circle circle = new Circle(new Point(condition.getLongitude(), condition.getLatitude()),
new Distance(condition.getRadius(), Metrics.KILOMETERS));
querys.addCriteria(Criteria.where("point").withinSphere(circle));
return mongoTemplate.count(querys, "resource");
// NearQuery query = NearQuery.near(new Point(condition.getLongitude(), condition.getLatitude())).query(querys)
// .maxDistance(new Distance(condition.getRadius(), Metrics.KILOMETERS));
// GeoResults<Object> geoResults = mongoTemplate.geoNear(query, Object.class, "resource");
// return geoResults.getContent().size();
}
/*--------------------------------------------------------------------------------------------------------------------------*/
// 分页获取矩形内点范围类数据
public PageInfo<AnalysisVo> getCircleBoxEventPage(EventCondition condition) {
Query querys = this.getCommonQuery(condition);
Box box = new Box(condition.getBox().get(0).stream().mapToDouble(Double::valueOf).toArray(),
condition.getBox().get(1).stream().mapToDouble(Double::valueOf).toArray());
querys.addCriteria(Criteria.where("point").within(box));
NearQuery query = NearQuery.near(new Point(condition.getLongitude(), condition.getLatitude())).query(querys)
.maxDistance(new Distance(condition.getRadius(), Metrics.KILOMETERS)).limit(condition.getPageSize())
.skip((condition.getPageNum() - 1) * condition.getPageSize());
GeoResults<Object> geoResults = mongoTemplate.geoNear(query, Object.class, "resource");
PageInfo<AnalysisVo> pageInfo = new PageInfo<>(DataUtil.convert(geoResults.getContent(), condition));
pageInfo.setTotal(this.getCircleBoxEventCount(condition));
pageInfo.setPageNum(condition.getPageNum());
pageInfo.setPageSize(condition.getPageSize());
return pageInfo;
}
// 获取矩形内点范围类数据
public List<AnalysisVo> getCircleBoxEvent(EventCondition condition) {
Query querys = this.getCommonQuery(condition);
Box box = new Box(condition.getBox().get(0).stream().mapToDouble(Double::valueOf).toArray(),condition.getBox().get(1).stream().mapToDouble(Double::valueOf).toArray());
querys.addCriteria(Criteria.where("point").within(box));
NearQuery query = NearQuery.near(new Point(condition.getLongitude(), condition.getLatitude()))
.maxDistance(new Distance(condition.getRadius(), Metrics.KILOMETERS)).query(querys)
.limit(condition.getPageSize())
.skip((condition.getPageNum() - 1) * condition.getPageSize());
GeoResults<Object> geoResults = mongoTemplate.geoNear(query, Object.class, "resource");
return DataUtil.convert(geoResults.getContent(),condition);
}
// 获取矩形内点范围类数据量
public Long getCircleBoxEventCount(EventCondition condition) {
Query querys = this.getCommonQuery(condition);
Box box = new Box(condition.getBox().get(0).stream().mapToDouble(Double::valueOf).toArray(),
condition.getBox().get(1).stream().mapToDouble(Double::valueOf).toArray());
Circle circle = new Circle(new Point(condition.getLongitude(), condition.getLatitude()),
new Distance(condition.getRadius(), Metrics.KILOMETERS));
querys.addCriteria(Criteria.where("point").withinSphere(circle).andOperator(Criteria.where("point").within(box)));
return mongoTemplate.count(querys, "resource");
// NearQuery query = NearQuery.near(new Point(condition.getLongitude(), condition.getLatitude())).query(querys)
// .maxDistance(new Distance(condition.getRadius(), Metrics.KILOMETERS));
// GeoResults<Object> geoResults = mongoTemplate.geoNear(query, Object.class, "resource");
// return geoResults.getContent().size();
}
/*--------------------------------------------------------------------------------------------------------------------------*/
// 获取多边形内点坐标范围类数据
public PageInfo<AnalysisVo> getCirclePolygonEventPage(EventCondition condition) {
Query querys = this.getCommonQuery(condition);
List<Point> points = new ArrayList<Point>();
Point point = null;
for (int i = 0; i < condition.getBox().size(); i++) {
Double X = condition.getBox().get(i).stream().mapToDouble(Double::valueOf).toArray()[0];
Double Y = condition.getBox().get(i).stream().mapToDouble(Double::valueOf).toArray()[1];
point = new Point(X, Y);
points.add(point);
}
Polygon poly = new Polygon(points);
querys.addCriteria(Criteria.where("point").within(poly));
NearQuery query = NearQuery.near(new Point(condition.getLongitude(), condition.getLatitude())).query(querys)
.maxDistance(new Distance(condition.getRadius(), Metrics.KILOMETERS)).limit(condition.getPageSize())
.skip((condition.getPageNum() - 1) * condition.getPageSize());
GeoResults<Object> geoResults = mongoTemplate.geoNear(query, Object.class, "resource");
PageInfo<AnalysisVo> pageInfo = new PageInfo<>(DataUtil.convert(geoResults.getContent(), condition));
pageInfo.setTotal(this.getCirclePolygonEventCount(condition));
pageInfo.setPageNum(condition.getPageNum());
pageInfo.setPageSize(condition.getPageSize());
return pageInfo;
}
// 获取多边形内点坐标范围类数据
public List<AnalysisVo> getCirclePolygonEvent(EventCondition condition) {
Query querys = this.getCommonQuery(condition);
List<Point> points = new ArrayList<Point>();
Point point = null;
for (int i = 0; i < condition.getBox().size(); i++) {
Double X = condition.getBox().get(i).stream().mapToDouble(Double::valueOf).toArray()[0];
Double Y = condition.getBox().get(i).stream().mapToDouble(Double::valueOf).toArray()[1];
point = new Point(X, Y);
points.add(point);
}
Polygon poly = new Polygon(points);
querys.addCriteria(Criteria.where("point").within(poly));
NearQuery query = NearQuery.near(new Point(condition.getLongitude(), condition.getLatitude()))
.maxDistance(new Distance(condition.getRadius(), Metrics.KILOMETERS)).query(querys)
.limit(condition.getPageSize())
.skip((condition.getPageNum() - 1) * condition.getPageSize());
GeoResults<Object> geoResults = mongoTemplate.geoNear(query, Object.class, "resource");
return DataUtil.convert(geoResults.getContent(),condition);
}
// 获取多边形内点坐标范围类数量
public Long getCirclePolygonEventCount(EventCondition condition) {
Query querys = this.getCommonQuery(condition);
List<Point> points = new ArrayList<Point>();
Point point = null;
for (int i = 0; i < condition.getBox().size(); i++) {
Double X = condition.getBox().get(i).stream().mapToDouble(Double::valueOf).toArray()[0];
Double Y = condition.getBox().get(i).stream().mapToDouble(Double::valueOf).toArray()[1];
point = new Point(X, Y);
points.add(point);
}
Polygon poly = new Polygon(points);
Circle circle = new Circle(new Point(condition.getLongitude(), condition.getLatitude()),
new Distance(condition.getRadius(), Metrics.KILOMETERS));
querys.addCriteria(Criteria.where("point").withinSphere(circle).andOperator(Criteria.where("point").within(poly)));
return mongoTemplate.count(querys, "resource");
// NearQuery query = NearQuery.near(new Point(condition.getLongitude(), condition.getLatitude())).query(querys)
// .maxDistance(new Distance(condition.getRadius(), Metrics.KILOMETERS));
// GeoResults<Object> geoResults = mongoTemplate.geoNear(query, Object.class, "resource");
// return geoResults.getContent().size();
}
/*--------------------------------------------------------------------------------------------------------------------------*/
//通用条件类
public Query getCommonQuery(EventCondition condition) {
Query querys = new Query();
List<String> typeList = new ArrayList<String>();
typeList.addAll(condition.getYjType());//应急类型
typeList.addAll(condition.getFhType());//防护类型
typeList.addAll(condition.getWxType());//危险源类型
typeList.addAll(condition.getSpType());//视频监控类型
querys.addCriteria(Criteria.where("typeCode").exists(true));//typeCode为空不计入统计
// 模块名
if (StringUtils.isNotEmpty(condition.getModuleName())) {
querys.addCriteria(Criteria.where("moduleName").is(condition.getModuleName()));
}
// 通用名称
if (StringUtils.isNotEmpty(condition.getName())) {
Pattern pattern = Pattern.compile("^.*" + condition.getName() + ".*$", Pattern.CASE_INSENSITIVE);
querys.addCriteria(Criteria.where("name").regex(pattern));
}
// 应急类型+防护类型+风险类型 + 区域
if (typeList.size() > 0 || condition.getArea().size() > 0) {
Criteria criteria = new Criteria();
List<Criteria> list1 = new ArrayList<Criteria>();
List<Criteria> list2 = new ArrayList<Criteria>();
Criteria criteria1 = new Criteria();
Criteria criteria2 = new Criteria();
//类别
for (String type : typeList) {
list1.add(Criteria.where("typeCode").is(type));
}
//区域
for (String area : condition.getArea()) {
Pattern pattern = Pattern.compile("^.*" + area + ".*$", Pattern.CASE_INSENSITIVE);
list2.add(Criteria.where("jsonObj").regex(pattern));
}
criteria1.orOperator(list1.stream().toArray(Criteria[]::new));
criteria2.orOperator(list2.stream().toArray(Criteria[]::new));
if (list1.size() + list2.size() > 0) {
// 没有等于号
if (list1.size() > 0 && list2.size() > 0) {
criteria.andOperator(criteria1, criteria2);
}
// 一个等于号
if (list1.size() == 0 && list2.size() > 0) {
criteria.andOperator(criteria2);
}
if (list1.size() > 0 && list2.size() == 0) {
criteria.andOperator(criteria1);
}
querys.addCriteria(criteria);
}
}
return querys;
}
}