1004 Counting Leaves (30 point(s))

本文介绍了一种算法,用于解决计算家族树中每个层级的叶子节点数量的问题。通过深度优先搜索(DFS)遍历树结构,标记并计算各层级的叶子节点数目。文章提供了一个C++实现示例,详细解释了如何从根节点开始,递归地访问每个节点,直到找到无子节点的叶子节点,并更新对应层级的计数。

1004 Counting Leaves (30 point(s))

A family hierarchy is usually presented by a pedigree tree. Your job is to count those family members who have no child.

Input Specification:

Each input file contains one test case. Each case starts with a line containing 0<N<100, the number of nodes in a tree, and M (<N), the number of non-leaf nodes. Then M lines follow, each in the format:

ID K ID[1] ID[2] ... ID[K]

where ID is a two-digit number representing a given non-leaf node, K is the number of its children, followed by a sequence of two-digit ID's of its children. For the sake of simplicity, let us fix the root ID to be 01.

The input ends with N being 0. That case must NOT be processed.

Output Specification:

For each test case, you are supposed to count those family members who have no child for every seniority levelstarting from the root. The numbers must be printed in a line, separated by a space, and there must be no extra space at the end of each line.

The sample case represents a tree with only 2 nodes, where 01 is the root and 02 is its only child. Hence on the root 01 level, there is 0 leaf node; and on the next level, there is 1 leaf node. Then we should output 0 1 in a line.

Sample Input:

2 1
01 1 02

Sample Output:

0 1

题意:计算一棵树的每一个层次的叶子节点。

思路:深度优先搜索(广度优先搜索也可以),注意标记每个结点所在的层次。直到该节点没有儿子节点结束,根据该节点的层次,cnt[]自增。

BFS参考大神链接:https://blog.youkuaiyun.com/richenyunqi/article/details/79533166

#include<iostream>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
const int MAX = 107;
vector<int> graph[MAX];
int level[MAX]={0};
int cnt[MAX]={0};
int maxLevel = 0;
void dfs(int v){
	if(graph[v].size()==0){
		cnt[level[v]]++;
		return;
	}
	for(int i=0;i<graph[v].size();i++){
		int cur = graph[v][i];
		level[cur]=level[v]+1;
		maxLevel = max(maxLevel,level[cur]);
		dfs(cur);
	}
}
int main(void){
	int N,M;cin>>N>>M;
	int id,k,a;
	while(M--){
		cin>>id>>k;
		while(k--){
			cin>>a;
			graph[id].push_back(a);
		}
	}
	int root = 1;
	dfs(root);
	for(int i=0;i<=maxLevel;i++){
		if(i==0) cout<<cnt[i];
		else cout<<" "<<cnt[i];
	}
	return 0;
} 

 

/* Copyright © 2025, TP-Link Global Inc. All rights reserved. */ package com.tplink.cdd.vms.ai.manager.core.domain.peoplecounting.trajectory; import java.io.BufferedWriter; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Paths; import java.nio.file.StandardOpenOption; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; import javax.annotation.PostConstruct; import com.tplink.cdd.vms.ai.manager.core.domain.faulttrackingpoint.annotation.TrackingPointEnable; import com.tplink.cdd.vms.ai.manager.core.domain.faulttrackingpoint.aspect.PeopleCountingTrackingPointCount; import com.tplink.cdd.vms.ai.manager.core.domain.peoplecounting.trajectory.tool.TrajectorRecognitionTool; import org.apache.skywalking.apm.toolkit.trace.Trace; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Lazy; import com.tplink.cdd.vms.ai.manager.core.domain.AiModule; import com.tplink.cdd.vms.ai.manager.core.domain.common.dto.Line; import com.tplink.cdd.vms.ai.manager.core.domain.common.dto.Point; import com.tplink.cdd.vms.ai.manager.core.domain.common.utils.GeometryUtils; import com.tplink.cdd.vms.ai.manager.core.domain.device.DeviceInfoContextCacheService; import com.tplink.cdd.vms.ai.manager.core.domain.passengerstatistics.dto.DeviceConfigDTO; import com.tplink.cdd.vms.ai.manager.core.domain.passengerstatistics.dto.IntersectionLineDTO; import com.tplink.cdd.vms.ai.manager.core.domain.passengerstatistics.enums.CrossAreaWayEnum; import com.tplink.cdd.vms.ai.manager.core.domain.peoplecounting.log.DynamicObjectLogger; import com.tplink.cdd.vms.ai.manager.core.domain.peoplecounting.trajectory.entity.DeviceEntity; import com.tplink.cdd.vms.ai.manager.core.domain.peoplecounting.trajectory.entity.DevicePointEntity; import com.tplink.cdd.vms.ai.manager.core.domain.peoplecounting.trajectory.entity.HistoricalEntity; import com.tplink.cdd.vms.ai.manager.core.domain.peoplecounting.trajectory.entity.ResultEntity; import com.tplink.cdd.vms.ai.manager.core.domain.smartdata.SmartDataFrame; import com.tplink.cdd.vms.ai.manager.core.domain.smartdata.processor.AbstractSmartDataHandler; import com.tplink.cdd.vms.ai.manager.core.domain.smartdata.processor.AiSmartDataProcessor; import com.tplink.cdd.vms.ai.manager.core.domain.threadpool.AiCustomThreadPool; import com.tplink.cdd.vms.ai.manager.core.infrastructure.cache.PeopleCountingCache; import com.tplink.cdd.vms.ai.manager.core.infrastructure.cache.PeopleCountingResultCache; import com.tplink.cdd.vms.ai.manager.core.infrastructure.cache.TrajectoryCache; import com.tplink.cdd.vms.ai.manager.core.infrastructure.cache.entity.PeopleCountingConfigEntity; import com.tplink.cdd.vms.ai.manager.core.port.config.AiSwitchConfig; import com.tplink.cdd.vms.ai.manager.core.port.dto.DeviceInfoContext; import com.tplink.cdd.vms.common.dto.OperationResponse; import com.tplink.cdd.vms.common.util.CollectionUtil; import com.tplink.cdd.vms.common.util.CustomPIIMaskUtil; import com.tplink.cdd.vms.common.util.JsonUtils; /** Description of this file @author hejun @version 1.0 @since 2025/8/11 */ public abstract class AbstractPeopleCountingHandler implements AbstractSmartDataHandler { @Lazy @Autowired protected PeopleCountingCache peopleCountingCache; @Lazy @Autowired protected PeopleCountingResultCache peopleCountingResultCache; @Autowired private AiSwitchConfig aiSwitchConfig; @Autowired private TrajectoryCache trajectoryCache; @Autowired private DeviceInfoContextCacheService deviceInfoContextCacheService; @Autowired private PeopleCountingTrackingPointCount peopleCountingTrackingPointCount; @Value(“${peopleCounting.trajectory.algorithm:multi_segments}”) private String trajectoryAlgorithm = “multi_segments”; @Value(“${peopleCounting.trajectory.sufficientDistanceTimes:2}”) private int sufficientDistanceTimes = 2; protected static final Set NEED_LOG_DEVICE_IDS = new HashSet<>(); private static final DynamicObjectLogger log = new DynamicObjectLogger( AbstractPeopleCountingHandler.class) { @Override public boolean debugEnabled(Long deviceId) { // todo return true; // return NEED_LOG_DEVICE_IDS.contains(deviceId); } }; protected abstract AiCustomThreadPool getThreadPool(); public abstract Collection getRealDeviceConfigs( T deviceEntity); protected abstract Boolean isBusinessTime(PeopleCountingConfigEntity deviceConfig); protected abstract Boolean isBusinessTime(HistoricalEntity history); public static void updateNeedLogDeviceIds(Collection deviceIds) { NEED_LOG_DEVICE_IDS.clear(); if (CollectionUtil.isNotEmpty(deviceIds)) { NEED_LOG_DEVICE_IDS.addAll(deviceIds); } } @PostConstruct public void init() { AiModule module = getModule(); log.info(1L, “peoples counting handler init, module {}, enabled {}.”, module, aiSwitchConfig.isAiModuleEnabled(module)); if (aiSwitchConfig.isAiModuleEnabled(module)) { AiSmartDataProcessor.registerHandler(module, this); } } @Trace @Override public void handleSmartData(DeviceInfoContext deviceInfo, SmartDataFrame frame) { Integer threadPoolIndex = deviceInfo.getPassengerFlowStatisticsThreadPoolIndex(); Long deviceId = deviceInfo.getDeviceId(); if (Objects.isNull(threadPoolIndex)) { int execute = getThreadPool().execute(deviceInfo.getKey(), () -> doHandleSmartData(deviceInfo, frame)); log.info(deviceId, “ai thread pool index [passenger flow stat] {}, device id {}, dev id {}, channel {}.”, execute, deviceId, CustomPIIMaskUtil.encrypt(deviceInfo.getDevId()), deviceInfo.getChannel()); deviceInfo.setPassengerFlowStatisticsThreadPoolIndex(execute); } else { getThreadPool().execute(threadPoolIndex, () -> doHandleSmartData(deviceInfo, frame)); } } @Trace private void doHandleSmartData(DeviceInfoContext deviceInfo, SmartDataFrame frame) { log.info(123L, “frame is {}”, frame); if (!verified(deviceInfo, frame)) { log.debug(deviceInfo.getDeviceId(), “invalid data, DeviceInfoContext: {}, SmartDataFrame: {}.”, deviceInfo, frame); return; } Long deviceId = deviceInfo.getDeviceId(); DeviceEntity deviceEntity = DeviceEntity.getDeviceEntity(deviceInfo); log.debug(deviceId, "deviceEntity is {}", deviceEntity); Collection<PeopleCountingConfigEntity> deviceConfigs = getDeviceConfigs(deviceEntity); if (CollectionUtil.isEmpty(deviceConfigs)) { log.debug(deviceId, "device config is empty"); return; } log.info(deviceId, "deviceConfigs is {}", deviceConfigs); List<DevicePointEntity> points = frame.getObjs().stream().map(DevicePointEntity::getDevicePointEntity) .filter(Objects::nonNull) .collect(Collectors.toList()); if (CollectionUtil.isEmpty(points)) { log.debug(deviceId, "points is empty, frame: {}.", frame); return; } Collection<ResultEntity> results = new HashSet<>(); long timeStamp = System.currentTimeMillis() / TimeUnit.MINUTES.toMillis(1); for (PeopleCountingConfigEntity deviceConfig : deviceConfigs) { // todo 并发处理 ResultEntity resultEntity = trajectoryRecognition(deviceEntity, deviceConfig, points); log.debug(deviceId, "resultEntity is {}.", resultEntity); if (Objects.nonNull(resultEntity)) { resultEntity.setTimeMinute(timeStamp); results.add(resultEntity); } } if (CollectionUtil.isEmpty(results)) { log.debug(deviceId, "results is empty, frame: {}.", frame); return; } peopleCountingResultCache.offers(results); } public Optional handleDisappearsData(HistoricalEntity history) { Long deviceId = history.getDeviceId(); CrossAreaWayEnum crossAreaWay = history.resetInside(sufficientDistanceTimes); if (Objects.equals(crossAreaWay, CrossAreaWayEnum.USELESS)) { return Optional.empty(); } ResultEntity resultEntity = history.generateResultEntity(); resultEntity.setBusinessTime(isBusinessTime(history)); switch (crossAreaWay) { case PASS_BY_STORE: resultEntity.setPassBy(1); return Optional.of(resultEntity); case ENTER_STORE: resultEntity.setEnter(1); return Optional.of(resultEntity); case LEAVE_STORE: resultEntity.setCheckOut(1); return Optional.of(resultEntity); default: log.debug(deviceId, “useless cross area way: {}”, crossAreaWay); } return Optional.empty(); } public Optional handleDisappearsData(String key, Line start, Line end) { Optional resultEntity = PeopleCountingCache.parseKey(key); if (!resultEntity.isPresent()) { return Optional.empty(); } ResultEntity result = resultEntity.get(); Long deviceId = result.getDeviceId(); int passBy = 0; int enter = 0; int checkOut = 0; try { CrossAreaWayEnum crossAreaWay = identifyDisappearsTrajectory(key, start, end); log.debug(deviceId, "cross area way: {}, key: {}, start: {}, end: {}.", crossAreaWay, key, start, end); switch (crossAreaWay) { case PASS_BY_STORE: passBy++; break; case ENTER_STORE: enter++; break; case LEAVE_STORE: checkOut++; break; default: log.debug(deviceId, "useless cross area way: {}", crossAreaWay); } } catch (Exception e) { log.debug(deviceId, "trajectory recognition error, key: {}, start: {}, end: {}.", key, start, end, e); } if (passBy == 0 && enter == 0 && checkOut == 0) { return Optional.empty(); } OperationResponse<DeviceInfoContext> deviceInfoContextByDeviceId = deviceInfoContextCacheService.getDeviceInfoContextByDeviceId( deviceId); if (deviceInfoContextByDeviceId.isError() || Objects.isNull(deviceInfoContextByDeviceId.getResult())) { log.debug(deviceId, "device info context is null, device id: {}.", deviceId); return Optional.empty(); } AiModule module = getModule(); result.setModule(module); result.setDeviceEntity(DeviceEntity.getDeviceEntity(deviceInfoContextByDeviceId.getResult())); Optional<PeopleCountingConfigEntity> deviceConfigOptional = peopleCountingCache.getConfigOptional(module, deviceId, result.getConfigId()); if (!deviceConfigOptional.isPresent()) { return Optional.empty(); } PeopleCountingConfigEntity deviceConfig = deviceConfigOptional.get(); result.setConfigId(deviceConfig.getConfigId()); result.setBusinessTime(isBusinessTime(deviceConfig)); result.setPassBy(passBy); result.setEnter(enter); result.setCheckOut(checkOut); result.setTimeMinute(System.currentTimeMillis() / TimeUnit.MINUTES.toMillis(1)); log.debug(deviceId, "trajectory recognition result: {}.", result); return Optional.of(result); } public CrossAreaWayEnum identifyDisappearsTrajectory(String key, Line start, Line end) { HistoricalEntity historical = peopleCountingCache.getHistorical(getModule(), key); if (Objects.isNull(historical)) { return CrossAreaWayEnum.USELESS; } List polygon = historical.getCurrentConfig().getPolygon(); Point outside = polygon.get(polygon.size() - 2); if (Boolean.TRUE.equals(historical.getCurrentConfig().getEnterFromA2B())) { outside = polygon.get(0); } Point enter; IntersectionLineDTO enterIntersectionLine = historical.getEnterIntersectionLine(); if (Objects.isNull(enterIntersectionLine)) { enterIntersectionLine = GeometryUtils.findRayIntersection(historical.getCurrentConfig().getPolygon(), start.reverse()); } enter = enterIntersectionLine.getIntersection(); IntersectionLineDTO leaveIntersectionLine = historical.getLeaveIntersectionLine(); if (Objects.isNull(leaveIntersectionLine)) { leaveIntersectionLine = GeometryUtils.findRayIntersection( historical.getCurrentConfig().getPolygon(), end); } Point leave = leaveIntersectionLine.getIntersection(); Line cuttingLine = historical.getCurrentConfig().getCuttingLine(); CrossAreaWayEnum crossAreaWay = getCrossAreaWay(enter, leave, cuttingLine, outside); log.debug(12L, "[PassengerFlowStatistics] getCrossAreaWay enter = {}, leave = {}, cuttingLine = {}, outside = {}.", enter, leave, cuttingLine, outside); reset(historical); return crossAreaWay; } private boolean verified(DeviceInfoContext deviceInfo, SmartDataFrame frame) { if (Objects.isNull(deviceInfo) || Objects.isNull(frame)) { return false; } if (Objects.isNull(deviceInfo.getDeviceId())) { return false; } if (CollectionUtil.isEmpty(frame.getObjs())) { return false; } return true; } private Collection getDeviceConfigs(DeviceEntity deviceEntity) { return peopleCountingCache.getDeviceConfigs(deviceEntity, getModule()); } @Trace private ResultEntity trajectoryRecognition(DeviceEntity deviceEntity, PeopleCountingConfigEntity deviceConfig, List points) { Long deviceId = deviceConfig.getDeviceId(); int passBy = 0; int enter = 0; int checkOut = 0; for (DevicePointEntity point : points) { HistoricalEntity historical = obtainHistorical(deviceEntity, deviceConfig, point.getObjectId()); log.debug(deviceId, “historical is {}”, historical); if (Objects.isNull(historical)) { continue; } try { CrossAreaWayEnum crossAreaWay = identifyTrajectory(historical, point); log.debug(deviceId, “cross area way: {}, historical: {}, point: {}.”, crossAreaWay, historical, point); switch (crossAreaWay) { case PASS_BY_STORE: passBy++; break; case ENTER_STORE: enter++; break; case LEAVE_STORE: checkOut++; break; default: log.debug(deviceId, “useless cross area way: {}”, crossAreaWay); } } catch (Exception e) { log.debug(deviceId, “trajectory recognition error, historical: {}, point: {}.”, historical, point, e); } } if (passBy == 0 && enter == 0 && checkOut == 0) { return null; } ResultEntity result = new ResultEntity(); result.setModule(getModule()); result.setDeviceEntity(deviceEntity); result.setConfigId(deviceConfig.getConfigId()); result.setBusinessTime(isBusinessTime(deviceConfig)); result.setPassBy(passBy); result.setEnter(enter); result.setCheckOut(checkOut); log.debug(deviceId, “trajectory recognition result: {}.”, result); return result; } private HistoricalEntity obtainHistorical(DeviceEntity deviceEntity, PeopleCountingConfigEntity deviceConfig, Integer objectId) { return peopleCountingCache.getHistorical(deviceEntity, deviceConfig.getConfigId(), objectId, getModule()); } private CrossAreaWayEnum identifyTrajectory(HistoricalEntity historical, DevicePointEntity point) { Long deviceId = historical.getDeviceId(); log.debug(deviceId, “[PassengerFlowStatistics] Start processing passenger flow statistics,HistoricalEntity = {}, current = {}.”, JsonUtils.bean2Json(historical), JsonUtils.bean2Json(point)); Point current = point.getPoint(); if (Objects.isNull(current)) { peopleCountingTrackingPointCount.getPeopleCountingTrackingPointData(historical, point, CrossAreaWayEnum.USELESS); return CrossAreaWayEnum.USELESS; } historical.setPrevious(historical.getCurrent()); historical.setPreviousInside(historical.getCurrentInside()); historical.setCurrent(current); historical.setCurrentInside(getPosition(historical.getDeviceConfigs(), current)); CrossAreaWayEnum crossAreaWayEnum = CrossAreaWayEnum.USELESS; log.debug(deviceId, "[PassengerFlowStatistics] The current node is located at {}", historical.getCurrentInside()); if (Objects.nonNull(historical.getCurrentInside())) { DeviceConfigDTO currentDeviceConfigDTO = historical.getDeviceConfigs().get(historical.getCurrentInside()); if (point.getConfidence() + currentDeviceConfigDTO.getSensitivity() < 100) { log.debug(deviceId, "[PassengerFlowStatistics] The node confidence does not meet the requirements, confidence = {}, Sensitivity = historical.currentDeviceConfigDTO.getSensitivity()", historical.getCurrentInside()); // 越不灵敏越不能接受置信度小的数据,如此灵敏度和置信度都很小的数据,丢弃 historical.setCurrent(historical.getPrevious()); historical.setCurrentInside(historical.getPreviousInside()); peopleCountingTrackingPointCount.getPeopleCountingTrackingPointData(historical, point, CrossAreaWayEnum.USELESS); return CrossAreaWayEnum.USELESS; } processTrajectoryCache(historical, point.getObjectId(), current, point.getBoxHeight()); historical.setCurrentConfig(currentDeviceConfigDTO); if (Objects.isNull(historical.getEnterIntersectionLine()) && ( Objects.equals(historical.getCurrentInside(), historical.getPreviousInside()) || Objects.isNull(historical.getPrevious()))) { log.debug(deviceId, "[PassengerFlowStatistics] There is no trajectory entering the area."); //判断是否在边界上,在边界上即为进入线 IntersectionLineDTO enterIntersectionLine = GeometryUtils.findIntersection( currentDeviceConfigDTO.getPolygon(), current); log.debug(deviceId, "[PassengerFlowStatistics] The result of judging whether current node is on the boundary is {}", enterIntersectionLine); if (Objects.isNull(enterIntersectionLine)) { // 没有进入边界的点,凭空出现在了区域内 peopleCountingTrackingPointCount.getPeopleCountingTrackingPointData(historical, point, CrossAreaWayEnum.USELESS); return CrossAreaWayEnum.USELESS; } historical.setEnterIntersectionLine(enterIntersectionLine); } // 位于区域内,那离开的位置就得重新计算 historical.setLeaveIntersectionLine(null); historical.setCompleteLeave(false); } else { // 位于区域外,但是还没完全进入,那就得重新计算进入位置 if (Boolean.FALSE.equals(historical.getCompleteEnter())) { historical.setEnterIntersectionLine(null); historical.setCompleteEnter(false); } crossAreaWayEnum = historical.resetInside(sufficientDistanceTimes); } if (Objects.nonNull(historical.getCurrentInside()) && Objects.isNull(historical.getPreviousInside())) { // 进入区域 if (Objects.isNull(historical.getPrevious())) { peopleCountingTrackingPointCount.getPeopleCountingTrackingPointData(historical, point, CrossAreaWayEnum.USELESS); return CrossAreaWayEnum.USELESS; } historical.setEnterIntersectionLine(GeometryUtils.findIntersection( historical.getCurrentConfig().getPolygon(), new Line(current, historical.getPrevious()))); log.debug(deviceId, "[PassengerFlowStatistics] The target enters the area from {}", historical.getEnterIntersectionLine()); } else if (Objects.isNull(historical.getCurrentInside()) && Objects.nonNull(historical.getPreviousInside())) { if (Objects.isNull(historical.getPrevious())) { peopleCountingTrackingPointCount.getPeopleCountingTrackingPointData(historical, point, CrossAreaWayEnum.USELESS); return CrossAreaWayEnum.USELESS; } historical.setLeaveIntersectionLine(GeometryUtils.findIntersection( historical.getCurrentConfig().getPolygon(), new Line(current, historical.getPrevious()))); log.debug(deviceId, "[PassengerFlowStatistics] The target leaves the area from {}", historical.getLeaveIntersectionLine()); } if (Objects.nonNull(historical.getEnterIntersectionLine()) && !Boolean.TRUE.equals( historical.getCompleteEnter())) { historical.setCompleteEnter( GeometryUtils.distanceToLineSegment(historical.getEnterIntersectionLine().getLine(), current) > point.getHalfWidth()); } if (Objects.nonNull(historical.getLeaveIntersectionLine()) && !Boolean.TRUE.equals( historical.getCompleteLeave())) { historical.setCompleteLeave( GeometryUtils.distanceToLineSegment(historical.getLeaveIntersectionLine().getLine(), current) > point.getHalfWidth()); } log.debug(deviceId, "[PassengerFlowStatistics] completeEnter = {}, completeLeave = {}", historical.getCompleteEnter(), historical.getCompleteLeave()); if (Objects.nonNull(historical.getLeaveIntersectionLine()) && Boolean.TRUE.equals( historical.getCompleteLeave())) { if (Objects.isNull(historical.getEnterIntersectionLine())) { if (Objects.equals(trajectoryAlgorithm, "multi_segments")) { // 未知区域进入,从轨迹方向进行确认 List<Line> segment = trajectoryCache.getSegment(getModule(), deviceId, historical.getConfigId(), point.getObjectId()); if (CollectionUtil.isNotEmpty(segment)) { historical.setEnterIntersectionLine( GeometryUtils.findRayIntersection(historical.getCurrentConfig().getPolygon(), segment.get(0).reverse())); } } else { log.debug(deviceId, "[PassengerFlowStatistics] getCrossAreaWay crossAreaWayEnum = {}.", crossAreaWayEnum); reset(historical, point); peopleCountingTrackingPointCount.getPeopleCountingTrackingPointData(historical, point, crossAreaWayEnum); return crossAreaWayEnum; } } if (Objects.nonNull(historical.getEnterIntersectionLine())) { // 完成了离开 List<Point> polygon = historical.getCurrentConfig().getPolygon(); Point outside = polygon.get(polygon.size() - 2); if (Boolean.TRUE.equals(historical.getCurrentConfig().getEnterFromA2B())) { outside = polygon.get(0); } Point enter = historical.getEnterIntersectionLine().getIntersection(); Point leave = historical.getLeaveIntersectionLine().getIntersection(); Line cuttingLine = historical.getCurrentConfig().getCuttingLine(); CrossAreaWayEnum crossAreaWay = getCrossAreaWay(enter, leave, cuttingLine, outside); log.debug(deviceId, "[PassengerFlowStatistics] getCrossAreaWay enter = {}, leave = {}, cuttingLine = {}, outside = {}.", enter, leave, cuttingLine, outside); reset(historical, point); peopleCountingTrackingPointCount.getPeopleCountingTrackingPointData(historical, point, crossAreaWay); return crossAreaWay; } } peopleCountingTrackingPointCount.getPeopleCountingTrackingPointData(historical, point, CrossAreaWayEnum.USELESS); return CrossAreaWayEnum.USELESS; } private void processTrajectoryCache(HistoricalEntity historical, Integer objectId, Point current, Integer boxHeight) { Long deviceId = historical.getDeviceId(); String configId = historical.getConfigId(); try { if (Objects.equals(trajectoryAlgorithm, “multi_segments”)) { trajectoryCache.addPoint(getModule(), deviceId, configId, objectId, current, boxHeight); } else { historical.updateInside(current, boxHeight); } } catch (Exception e) { log.error(deviceId, “trajectory cache add point error, ai module = {}, deviceId = {}, configId = {}, objectId = {}, current = {}.”, getModule(), deviceId, configId, objectId, current, e); } } public boolean reset(HistoricalEntity historical, DevicePointEntity point) { trajectoryCache.reset(getModule(), historical.getDeviceId(), historical.getConfigId(), point.getObjectId()); return reset(historical); } public boolean reset(HistoricalEntity historical) { historical.setPrevious(null); historical.setPreviousInside(null); historical.setEnterIntersectionLine(null); historical.setCompleteEnter(null); historical.setLeaveIntersectionLine(null); historical.setCompleteLeave(null); return true; } public static Integer getPosition( Map<Integer, DeviceConfigDTO> deviceConfigs, Point point) { if (CollectionUtil.isEmpty(deviceConfigs) || point == null) { return null; } for (DeviceConfigDTO deviceConfig : deviceConfigs.values()) { if (GeometryUtils.isPointInPolygon(deviceConfig.getPolygon(), point)) { // 区域不重复,如果处于一个区域内,那必然不在另一个区域内 return deviceConfig.getId(); } } return null; } public static CrossAreaWayEnum getCrossAreaWay(Point enter, Point leave, Line cuttingLine, Point outside) { boolean fromOutside = GeometryUtils.arePointsOnSameSide(cuttingLine, enter, outside); boolean toOutside = GeometryUtils.arePointsOnSameSide(cuttingLine, leave, outside); if (fromOutside) { if (toOutside) { return CrossAreaWayEnum.PASS_BY_STORE; } return CrossAreaWayEnum.ENTER_STORE; } if (toOutside) { return CrossAreaWayEnum.LEAVE_STORE; } return CrossAreaWayEnum.USELESS; } } 这是我的一个类,我想要对identifyTrajectory方法使用springaop,一个怎么修改
10-15
我在package com.tplink.cdd.vms.ai.manager.core.domain.peoplecounting.trajectory;包下的public abstract class AbstractPeopleCountingHandler implements AbstractSmartDataHandler类中有一个方法private CrossAreaWayEnum identifyTrajectory(HistoricalEntity historical, DevicePointEntity point) { String filePath = "D:\\UserData\\Desktop\\2.txt"; try (BufferedWriter writer = Files.newBufferedWriter(Paths.get(filePath), StandardCharsets.UTF_8, StandardOpenOption.CREATE, StandardOpenOption.APPEND)) { // 写入内容并换行 writer.write("===正常执行==="); writer.newLine(); writer.flush(); } catch (IOException e) { } Long deviceId = historical.getDeviceId(); log.debug(deviceId, "[PassengerFlowStatistics] Start processing passenger flow statistics,HistoricalEntity = {}, current = {}.", JsonUtils.bean2Json(historical), JsonUtils.bean2Json(point)); Point current = point.getPoint(); if (Objects.isNull(current)) { return CrossAreaWayEnum.USELESS; } historical.setPrevious(historical.getCurrent()); historical.setPreviousInside(historical.getCurrentInside()); historical.setCurrent(current); historical.setCurrentInside(getPosition(historical.getDeviceConfigs(), current)); CrossAreaWayEnum crossAreaWayEnum = CrossAreaWayEnum.USELESS; log.debug(deviceId, "[PassengerFlowStatistics] The current node is located at {}", historical.getCurrentInside()); if (Objects.nonNull(historical.getCurrentInside())) { DeviceConfigDTO currentDeviceConfigDTO = historical.getDeviceConfigs().get(historical.getCurrentInside()); if (point.getConfidence() + currentDeviceConfigDTO.getSensitivity() < 100) { log.debug(deviceId, "[PassengerFlowStatistics] The node confidence does not meet the requirements, confidence = {}, Sensitivity = historical.currentDeviceConfigDTO.getSensitivity()", historical.getCurrentInside()); // 越不灵敏越不能接受置信度小的数据,如此灵敏度和置信度都很小的数据,丢弃 historical.setCurrent(historical.getPrevious()); historical.setCurrentInside(historical.getPreviousInside()); return CrossAreaWayEnum.USELESS; } processTrajectoryCache(historical, point.getObjectId(), current, point.getBoxHeight()); historical.setCurrentConfig(currentDeviceConfigDTO); if (Objects.isNull(historical.getEnterIntersectionLine()) && ( Objects.equals(historical.getCurrentInside(), historical.getPreviousInside()) || Objects.isNull(historical.getPrevious()))) { log.debug(deviceId, "[PassengerFlowStatistics] There is no trajectory entering the area."); //判断是否在边界上,在边界上即为进入线 IntersectionLineDTO enterIntersectionLine = GeometryUtils.findIntersection( currentDeviceConfigDTO.getPolygon(), current); log.debug(deviceId, "[PassengerFlowStatistics] The result of judging whether current node is on the boundary is {}", enterIntersectionLine); if (Objects.isNull(enterIntersectionLine)) { // 没有进入边界的点,凭空出现在了区域内 return CrossAreaWayEnum.USELESS; } historical.setEnterIntersectionLine(enterIntersectionLine); } // 位于区域内,那离开的位置就得重新计算 historical.setLeaveIntersectionLine(null); historical.setCompleteLeave(false); } else { // 位于区域外,但是还没完全进入,那就得重新计算进入位置 if (Boolean.FALSE.equals(historical.getCompleteEnter())) { historical.setEnterIntersectionLine(null); historical.setCompleteEnter(false); } crossAreaWayEnum = historical.resetInside(sufficientDistanceTimes); } if (Objects.nonNull(historical.getCurrentInside()) && Objects.isNull(historical.getPreviousInside())) { // 进入区域 if (Objects.isNull(historical.getPrevious())) { return CrossAreaWayEnum.USELESS; } historical.setEnterIntersectionLine(GeometryUtils.findIntersection( historical.getCurrentConfig().getPolygon(), new Line(current, historical.getPrevious()))); log.debug(deviceId, "[PassengerFlowStatistics] The target enters the area from {}", historical.getEnterIntersectionLine()); } else if (Objects.isNull(historical.getCurrentInside()) && Objects.nonNull(historical.getPreviousInside())) { if (Objects.isNull(historical.getPrevious())) { return CrossAreaWayEnum.USELESS; } historical.setLeaveIntersectionLine(GeometryUtils.findIntersection( historical.getCurrentConfig().getPolygon(), new Line(current, historical.getPrevious()))); log.debug(deviceId, "[PassengerFlowStatistics] The target leaves the area from {}", historical.getLeaveIntersectionLine()); } if (Objects.nonNull(historical.getEnterIntersectionLine()) && !Boolean.TRUE.equals( historical.getCompleteEnter())) { historical.setCompleteEnter( GeometryUtils.distanceToLineSegment(historical.getEnterIntersectionLine().getLine(), current) > point.getHalfWidth()); } if (Objects.nonNull(historical.getLeaveIntersectionLine()) && !Boolean.TRUE.equals( historical.getCompleteLeave())) { historical.setCompleteLeave( GeometryUtils.distanceToLineSegment(historical.getLeaveIntersectionLine().getLine(), current) > point.getHalfWidth()); } log.debug(deviceId, "[PassengerFlowStatistics] completeEnter = {}, completeLeave = {}", historical.getCompleteEnter(), historical.getCompleteLeave()); if (Objects.nonNull(historical.getLeaveIntersectionLine()) && Boolean.TRUE.equals( historical.getCompleteLeave())) { if (Objects.isNull(historical.getEnterIntersectionLine())) { if (Objects.equals(trajectoryAlgorithm, "multi_segments")) { // 未知区域进入,从轨迹方向进行确认 List<Line> segment = trajectoryCache.getSegment(getModule(), deviceId, historical.getConfigId(), point.getObjectId()); if (CollectionUtil.isNotEmpty(segment)) { historical.setEnterIntersectionLine( GeometryUtils.findRayIntersection(historical.getCurrentConfig().getPolygon(), segment.get(0).reverse())); } } else { log.debug(deviceId, "[PassengerFlowStatistics] getCrossAreaWay crossAreaWayEnum = {}.", crossAreaWayEnum); reset(historical, point); return crossAreaWayEnum; } } if (Objects.nonNull(historical.getEnterIntersectionLine())) { // 完成了离开 List<Point> polygon = historical.getCurrentConfig().getPolygon(); Point outside = polygon.get(polygon.size() - 2); if (Boolean.TRUE.equals(historical.getCurrentConfig().getEnterFromA2B())) { outside = polygon.get(0); } Point enter = historical.getEnterIntersectionLine().getIntersection(); Point leave = historical.getLeaveIntersectionLine().getIntersection(); Line cuttingLine = historical.getCurrentConfig().getCuttingLine(); CrossAreaWayEnum crossAreaWay = getCrossAreaWay(enter, leave, cuttingLine, outside); log.debug(deviceId, "[PassengerFlowStatistics] getCrossAreaWay enter = {}, leave = {}, cuttingLine = {}, outside = {}.", enter, leave, cuttingLine, outside); reset(historical, point); return crossAreaWay; } } return CrossAreaWayEnum.USELESS; } 现在希望使用aspectj而不是springaop获取方法的参数和返回值,因为该方法是在同一个类中被调用,所以springaop不行
10-12
public abstract class AbstractPeopleCountingHandler implements AbstractSmartDataHandler { @Lazy @Autowired protected PeopleCountingCache peopleCountingCache; @Lazy @Autowired protected PeopleCountingResultCache peopleCountingResultCache; @Autowired private AiSwitchConfig aiSwitchConfig; @Autowired private TrajectoryCache trajectoryCache; @Autowired private DeviceInfoContextCacheService deviceInfoContextCacheService; @Value("${peopleCounting.trajectory.algorithm:multi_segments}") private String trajectoryAlgorithm = "multi_segments"; @Value("${peopleCounting.trajectory.sufficientDistanceTimes:2}") private int sufficientDistanceTimes = 2; protected static final Set<Long> NEED_LOG_DEVICE_IDS = new HashSet<>(); private static final DynamicObjectLogger<Long> log = new DynamicObjectLogger<Long>( AbstractPeopleCountingHandler.class) { @Override public boolean debugEnabled(Long deviceId) { // todo return true; // return NEED_LOG_DEVICE_IDS.contains(deviceId); } }; protected abstract AiCustomThreadPool getThreadPool(); public abstract <T extends DeviceEntity> Collection<PeopleCountingConfigEntity> getRealDeviceConfigs( T deviceEntity); protected abstract Boolean isBusinessTime(PeopleCountingConfigEntity deviceConfig); protected abstract Boolean isBusinessTime(HistoricalEntity history); public static void updateNeedLogDeviceIds(Collection<Long> deviceIds) { NEED_LOG_DEVICE_IDS.clear(); if (CollectionUtil.isNotEmpty(deviceIds)) { NEED_LOG_DEVICE_IDS.addAll(deviceIds); } } @PostConstruct public void init() { AiModule module = getModule(); log.info(1L, "peoples counting handler init, module {}, enabled {}.", module, aiSwitchConfig.isAiModuleEnabled(module)); if (aiSwitchConfig.isAiModuleEnabled(module)) { AiSmartDataProcessor.registerHandler(module, this); } } @Trace @Override public void handleSmartData(DeviceInfoContext deviceInfo, SmartDataFrame frame) { Integer threadPoolIndex = deviceInfo.getPassengerFlowStatisticsThreadPoolIndex(); Long deviceId = deviceInfo.getDeviceId(); if (Objects.isNull(threadPoolIndex)) { int execute = getThreadPool().execute(deviceInfo.getKey(), () -> doHandleSmartData(deviceInfo, frame)); log.info(deviceId, "ai thread pool index [passenger flow stat] {}, device id {}, dev id {}, channel {}.", execute, deviceId, CustomPIIMaskUtil.encrypt(deviceInfo.getDevId()), deviceInfo.getChannel()); deviceInfo.setPassengerFlowStatisticsThreadPoolIndex(execute); } else { getThreadPool().execute(threadPoolIndex, () -> doHandleSmartData(deviceInfo, frame)); } } @Trace private void doHandleSmartData(DeviceInfoContext deviceInfo, SmartDataFrame frame) { log.info(123L, "frame is {}", frame); if (!verified(deviceInfo, frame)) { log.debug(deviceInfo.getDeviceId(), "invalid data, DeviceInfoContext: {}, SmartDataFrame: {}.", deviceInfo, frame); return; } Long deviceId = deviceInfo.getDeviceId(); DeviceEntity deviceEntity = DeviceEntity.getDeviceEntity(deviceInfo); log.debug(deviceId, "deviceEntity is {}", deviceEntity); Collection<PeopleCountingConfigEntity> deviceConfigs = getDeviceConfigs(deviceEntity); if (CollectionUtil.isEmpty(deviceConfigs)) { log.debug(deviceId, "device config is empty"); return; } log.info(deviceId, "deviceConfigs is {}", deviceConfigs); List<DevicePointEntity> points = frame.getObjs().stream().map(DevicePointEntity::getDevicePointEntity) .filter(Objects::nonNull) .collect(Collectors.toList()); if (CollectionUtil.isEmpty(points)) { log.debug(deviceId, "points is empty, frame: {}.", frame); return; } Collection<ResultEntity> results = new HashSet<>(); long timeStamp = System.currentTimeMillis() / TimeUnit.MINUTES.toMillis(1); for (PeopleCountingConfigEntity deviceConfig : deviceConfigs) { // todo 并发处理 ResultEntity resultEntity = trajectoryRecognition(deviceEntity, deviceConfig, points); log.debug(deviceId, "resultEntity is {}.", resultEntity); if (Objects.nonNull(resultEntity)) { resultEntity.setTimeMinute(timeStamp); results.add(resultEntity); } } if (CollectionUtil.isEmpty(results)) { log.debug(deviceId, "results is empty, frame: {}.", frame); return; } peopleCountingResultCache.offers(results); } public Optional<ResultEntity> handleDisappearsData(HistoricalEntity history) { Long deviceId = history.getDeviceId(); CrossAreaWayEnum crossAreaWay = history.resetInside(sufficientDistanceTimes); if (Objects.equals(crossAreaWay, CrossAreaWayEnum.USELESS)) { return Optional.empty(); } ResultEntity resultEntity = history.generateResultEntity(); resultEntity.setBusinessTime(isBusinessTime(history)); switch (crossAreaWay) { case PASS_BY_STORE: resultEntity.setPassBy(1); return Optional.of(resultEntity); case ENTER_STORE: resultEntity.setEnter(1); return Optional.of(resultEntity); case LEAVE_STORE: resultEntity.setCheckOut(1); return Optional.of(resultEntity); default: log.debug(deviceId, "useless cross area way: {}", crossAreaWay); } return Optional.empty(); } public Optional<ResultEntity> handleDisappearsData(String key, Line start, Line end) { Optional<ResultEntity> resultEntity = PeopleCountingCache.parseKey(key); if (!resultEntity.isPresent()) { return Optional.empty(); } ResultEntity result = resultEntity.get(); Long deviceId = result.getDeviceId(); int passBy = 0; int enter = 0; int checkOut = 0; try { CrossAreaWayEnum crossAreaWay = identifyDisappearsTrajectory(key, start, end); log.debug(deviceId, "cross area way: {}, key: {}, start: {}, end: {}.", crossAreaWay, key, start, end); switch (crossAreaWay) { case PASS_BY_STORE: passBy++; break; case ENTER_STORE: enter++; break; case LEAVE_STORE: checkOut++; break; default: log.debug(deviceId, "useless cross area way: {}", crossAreaWay); } } catch (Exception e) { log.debug(deviceId, "trajectory recognition error, key: {}, start: {}, end: {}.", key, start, end, e); } if (passBy == 0 && enter == 0 && checkOut == 0) { return Optional.empty(); } OperationResponse<DeviceInfoContext> deviceInfoContextByDeviceId = deviceInfoContextCacheService.getDeviceInfoContextByDeviceId( deviceId); if (deviceInfoContextByDeviceId.isError() || Objects.isNull(deviceInfoContextByDeviceId.getResult())) { log.debug(deviceId, "device info context is null, device id: {}.", deviceId); return Optional.empty(); } AiModule module = getModule(); result.setModule(module); result.setDeviceEntity(DeviceEntity.getDeviceEntity(deviceInfoContextByDeviceId.getResult())); Optional<PeopleCountingConfigEntity> deviceConfigOptional = peopleCountingCache.getConfigOptional(module, deviceId, result.getConfigId()); if (!deviceConfigOptional.isPresent()) { return Optional.empty(); } PeopleCountingConfigEntity deviceConfig = deviceConfigOptional.get(); result.setConfigId(deviceConfig.getConfigId()); result.setBusinessTime(isBusinessTime(deviceConfig)); result.setPassBy(passBy); result.setEnter(enter); result.setCheckOut(checkOut); result.setTimeMinute(System.currentTimeMillis() / TimeUnit.MINUTES.toMillis(1)); log.debug(deviceId, "trajectory recognition result: {}.", result); return Optional.of(result); } public CrossAreaWayEnum identifyDisappearsTrajectory(String key, Line start, Line end) { HistoricalEntity historical = peopleCountingCache.getHistorical(getModule(), key); if (Objects.isNull(historical)) { return CrossAreaWayEnum.USELESS; } List<Point> polygon = historical.getCurrentConfig().getPolygon(); Point outside = polygon.get(polygon.size() - 2); if (Boolean.TRUE.equals(historical.getCurrentConfig().getEnterFromA2B())) { outside = polygon.get(0); } Point enter; IntersectionLineDTO enterIntersectionLine = historical.getEnterIntersectionLine(); if (Objects.isNull(enterIntersectionLine)) { enterIntersectionLine = GeometryUtils.findRayIntersection(historical.getCurrentConfig().getPolygon(), start.reverse()); } enter = enterIntersectionLine.getIntersection(); IntersectionLineDTO leaveIntersectionLine = historical.getLeaveIntersectionLine(); if (Objects.isNull(leaveIntersectionLine)) { leaveIntersectionLine = GeometryUtils.findRayIntersection( historical.getCurrentConfig().getPolygon(), end); } Point leave = leaveIntersectionLine.getIntersection(); Line cuttingLine = historical.getCurrentConfig().getCuttingLine(); CrossAreaWayEnum crossAreaWay = getCrossAreaWay(enter, leave, cuttingLine, outside); log.debug(12L, "[PassengerFlowStatistics] getCrossAreaWay enter = {}, leave = {}, cuttingLine = {}, outside = {}.", enter, leave, cuttingLine, outside); reset(historical); return crossAreaWay; } private boolean verified(DeviceInfoContext deviceInfo, SmartDataFrame frame) { if (Objects.isNull(deviceInfo) || Objects.isNull(frame)) { return false; } if (Objects.isNull(deviceInfo.getDeviceId())) { return false; } if (CollectionUtil.isEmpty(frame.getObjs())) { return false; } return true; } private Collection<PeopleCountingConfigEntity> getDeviceConfigs(DeviceEntity deviceEntity) { return peopleCountingCache.getDeviceConfigs(deviceEntity, getModule()); } @Trace private ResultEntity trajectoryRecognition(DeviceEntity deviceEntity, PeopleCountingConfigEntity deviceConfig, List<DevicePointEntity> points) { Long deviceId = deviceConfig.getDeviceId(); int passBy = 0; int enter = 0; int checkOut = 0; for (DevicePointEntity point : points) { HistoricalEntity historical = obtainHistorical(deviceEntity, deviceConfig, point.getObjectId()); log.debug(deviceId, "historical is {}", historical); if (Objects.isNull(historical)) { continue; } try { CrossAreaWayEnum crossAreaWay = identifyTrajectory(historical, point); log.debug(deviceId, "cross area way: {}, historical: {}, point: {}.", crossAreaWay, historical, point); switch (crossAreaWay) { case PASS_BY_STORE: passBy++; break; case ENTER_STORE: enter++; break; case LEAVE_STORE: checkOut++; break; default: log.debug(deviceId, "useless cross area way: {}", crossAreaWay); } } catch (Exception e) { log.debug(deviceId, "trajectory recognition error, historical: {}, point: {}.", historical, point, e); } } if (passBy == 0 && enter == 0 && checkOut == 0) { return null; } ResultEntity result = new ResultEntity(); result.setModule(getModule()); result.setDeviceEntity(deviceEntity); result.setConfigId(deviceConfig.getConfigId()); result.setBusinessTime(isBusinessTime(deviceConfig)); result.setPassBy(passBy); result.setEnter(enter); result.setCheckOut(checkOut); log.debug(deviceId, "trajectory recognition result: {}.", result); return result; } private HistoricalEntity obtainHistorical(DeviceEntity deviceEntity, PeopleCountingConfigEntity deviceConfig, Integer objectId) { return peopleCountingCache.getHistorical(deviceEntity, deviceConfig.getConfigId(), objectId, getModule()); } private CrossAreaWayEnum identifyTrajectory(HistoricalEntity historical, DevicePointEntity point) { Long deviceId = historical.getDeviceId(); log.debug(deviceId, "[PassengerFlowStatistics] Start processing passenger flow statistics,HistoricalEntity = {}, current = {}.", JsonUtils.bean2Json(historical), JsonUtils.bean2Json(point)); Point current = point.getPoint(); if (Objects.isNull(current)) { return CrossAreaWayEnum.USELESS; } historical.setPrevious(historical.getCurrent()); historical.setPreviousInside(historical.getCurrentInside()); historical.setCurrent(current); historical.setCurrentInside(getPosition(historical.getDeviceConfigs(), current)); CrossAreaWayEnum crossAreaWayEnum = CrossAreaWayEnum.USELESS; log.debug(deviceId, "[PassengerFlowStatistics] The current node is located at {}", historical.getCurrentInside()); if (Objects.nonNull(historical.getCurrentInside())) { DeviceConfigDTO currentDeviceConfigDTO = historical.getDeviceConfigs().get(historical.getCurrentInside()); if (point.getConfidence() + currentDeviceConfigDTO.getSensitivity() < 100) { log.debug(deviceId, "[PassengerFlowStatistics] The node confidence does not meet the requirements, confidence = {}, Sensitivity = historical.currentDeviceConfigDTO.getSensitivity()", historical.getCurrentInside()); // 越不灵敏越不能接受置信度小的数据,如此灵敏度和置信度都很小的数据,丢弃 historical.setCurrent(historical.getPrevious()); historical.setCurrentInside(historical.getPreviousInside()); return CrossAreaWayEnum.USELESS; } processTrajectoryCache(historical, point.getObjectId(), current, point.getBoxHeight()); historical.setCurrentConfig(currentDeviceConfigDTO); if (Objects.isNull(historical.getEnterIntersectionLine()) && ( Objects.equals(historical.getCurrentInside(), historical.getPreviousInside()) || Objects.isNull(historical.getPrevious()))) { log.debug(deviceId, "[PassengerFlowStatistics] There is no trajectory entering the area."); //判断是否在边界上,在边界上即为进入线 IntersectionLineDTO enterIntersectionLine = GeometryUtils.findIntersection( currentDeviceConfigDTO.getPolygon(), current); log.debug(deviceId, "[PassengerFlowStatistics] The result of judging whether current node is on the boundary is {}", enterIntersectionLine); if (Objects.isNull(enterIntersectionLine)) { // 没有进入边界的点,凭空出现在了区域内 return CrossAreaWayEnum.USELESS; } historical.setEnterIntersectionLine(enterIntersectionLine); } // 位于区域内,那离开的位置就得重新计算 historical.setLeaveIntersectionLine(null); historical.setCompleteLeave(false); } else { // 位于区域外,但是还没完全进入,那就得重新计算进入位置 if (Boolean.FALSE.equals(historical.getCompleteEnter())) { historical.setEnterIntersectionLine(null); historical.setCompleteEnter(false); } crossAreaWayEnum = historical.resetInside(sufficientDistanceTimes); } if (Objects.nonNull(historical.getCurrentInside()) && Objects.isNull(historical.getPreviousInside())) { // 进入区域 if (Objects.isNull(historical.getPrevious())) { return CrossAreaWayEnum.USELESS; } historical.setEnterIntersectionLine(GeometryUtils.findIntersection( historical.getCurrentConfig().getPolygon(), new Line(current, historical.getPrevious()))); log.debug(deviceId, "[PassengerFlowStatistics] The target enters the area from {}", historical.getEnterIntersectionLine()); } else if (Objects.isNull(historical.getCurrentInside()) && Objects.nonNull(historical.getPreviousInside())) { if (Objects.isNull(historical.getPrevious())) { return CrossAreaWayEnum.USELESS; } historical.setLeaveIntersectionLine(GeometryUtils.findIntersection( historical.getCurrentConfig().getPolygon(), new Line(current, historical.getPrevious()))); log.debug(deviceId, "[PassengerFlowStatistics] The target leaves the area from {}", historical.getLeaveIntersectionLine()); } if (Objects.nonNull(historical.getEnterIntersectionLine()) && !Boolean.TRUE.equals( historical.getCompleteEnter())) { historical.setCompleteEnter( GeometryUtils.distanceToLineSegment(historical.getEnterIntersectionLine().getLine(), current) > point.getHalfWidth()); } if (Objects.nonNull(historical.getLeaveIntersectionLine()) && !Boolean.TRUE.equals( historical.getCompleteLeave())) { historical.setCompleteLeave( GeometryUtils.distanceToLineSegment(historical.getLeaveIntersectionLine().getLine(), current) > point.getHalfWidth()); } log.debug(deviceId, "[PassengerFlowStatistics] completeEnter = {}, completeLeave = {}", historical.getCompleteEnter(), historical.getCompleteLeave()); if (Objects.nonNull(historical.getLeaveIntersectionLine()) && Boolean.TRUE.equals( historical.getCompleteLeave())) { if (Objects.isNull(historical.getEnterIntersectionLine())) { if (Objects.equals(trajectoryAlgorithm, "multi_segments")) { // 未知区域进入,从轨迹方向进行确认 List<Line> segment = trajectoryCache.getSegment(getModule(), deviceId, historical.getConfigId(), point.getObjectId()); if (CollectionUtil.isNotEmpty(segment)) { historical.setEnterIntersectionLine( GeometryUtils.findRayIntersection(historical.getCurrentConfig().getPolygon(), segment.get(0).reverse())); } } else { log.debug(deviceId, "[PassengerFlowStatistics] getCrossAreaWay crossAreaWayEnum = {}.", crossAreaWayEnum); reset(historical, point); return crossAreaWayEnum; } } if (Objects.nonNull(historical.getEnterIntersectionLine())) { // 完成了离开 List<Point> polygon = historical.getCurrentConfig().getPolygon(); Point outside = polygon.get(polygon.size() - 2); if (Boolean.TRUE.equals(historical.getCurrentConfig().getEnterFromA2B())) { outside = polygon.get(0); } Point enter = historical.getEnterIntersectionLine().getIntersection(); Point leave = historical.getLeaveIntersectionLine().getIntersection(); Line cuttingLine = historical.getCurrentConfig().getCuttingLine(); CrossAreaWayEnum crossAreaWay = getCrossAreaWay(enter, leave, cuttingLine, outside); log.debug(deviceId, "[PassengerFlowStatistics] getCrossAreaWay enter = {}, leave = {}, cuttingLine = {}, outside = {}.", enter, leave, cuttingLine, outside); reset(historical, point); return crossAreaWay; } } return CrossAreaWayEnum.USELESS; } private void processTrajectoryCache(HistoricalEntity historical, Integer objectId, Point current, Integer boxHeight) { Long deviceId = historical.getDeviceId(); String configId = historical.getConfigId(); try { if (Objects.equals(trajectoryAlgorithm, "multi_segments")) { trajectoryCache.addPoint(getModule(), deviceId, configId, objectId, current, boxHeight); } else { historical.updateInside(current, boxHeight); } } catch (Exception e) { log.error(deviceId, "trajectory cache add point error, ai module = {}, deviceId = {}, configId = {}, objectId = {}, current = {}.", getModule(), deviceId, configId, objectId, current, e); } } public boolean reset(HistoricalEntity historical, DevicePointEntity point) { trajectoryCache.reset(getModule(), historical.getDeviceId(), historical.getConfigId(), point.getObjectId()); return reset(historical); } public boolean reset(HistoricalEntity historical) { historical.setPrevious(null); historical.setPreviousInside(null); historical.setEnterIntersectionLine(null); historical.setCompleteEnter(null); historical.setLeaveIntersectionLine(null); historical.setCompleteLeave(null); return true; } public static Integer getPosition( Map<Integer, DeviceConfigDTO> deviceConfigs, Point point) { if (CollectionUtil.isEmpty(deviceConfigs) || point == null) { return null; } for (DeviceConfigDTO deviceConfig : deviceConfigs.values()) { if (GeometryUtils.isPointInPolygon(deviceConfig.getPolygon(), point)) { // 区域不重复,如果处于一个区域内,那必然不在另一个区域内 return deviceConfig.getId(); } } return null; } public static CrossAreaWayEnum getCrossAreaWay(Point enter, Point leave, Line cuttingLine, Point outside) { boolean fromOutside = GeometryUtils.arePointsOnSameSide(cuttingLine, enter, outside); boolean toOutside = GeometryUtils.arePointsOnSameSide(cuttingLine, leave, outside); if (fromOutside) { if (toOutside) { return CrossAreaWayEnum.PASS_BY_STORE; } return CrossAreaWayEnum.ENTER_STORE; } if (toOutside) { return CrossAreaWayEnum.LEAVE_STORE; } return CrossAreaWayEnum.USELESS; } } 添加行级注释
09-13
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值