VmsManageService.java 94 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749
  1. package com.its.vms.service;
  2. import com.its.app.utils.Elapsed;
  3. import com.its.app.utils.FloodFill;
  4. import com.its.app.utils.ItsUtils;
  5. import com.its.vms.config.ApplicationConfig;
  6. import com.its.vms.config.DebugConfig;
  7. import com.its.vms.dao.mapper.VmsManageMapper;
  8. import com.its.vms.domain.VmsConstants;
  9. import com.its.vms.domain.VmsForm;
  10. import com.its.vms.domain.VmsFormObject;
  11. import com.its.vms.domain.VmsSchedule;
  12. import com.its.vms.domain.enums.eTrafficGrade;
  13. import com.its.vms.domain.enums.eVmsColor;
  14. import com.its.vms.domain.enums.eVmsFormType;
  15. import com.its.vms.domain.enums.eVmsScheduleType;
  16. import com.its.vms.dto.*;
  17. import com.its.vms.entity.TbVmsIncd;
  18. import com.its.vms.entity.TbVmsOperMode;
  19. import com.its.vms.entity.TbVmsSchedule;
  20. import com.its.vms.process.DbmsData;
  21. import com.its.vms.process.DbmsDataProcess;
  22. import com.its.vms.process.DbmsDataType;
  23. import com.its.vms.xnettcp.vms.process.TcpServerSendData;
  24. import com.its.vms.xnettcp.vms.protocol.enums.eVmsFormObjectKind;
  25. import com.its.vms.xnettcp.vms.protocol.enums.eVmsOpCode;
  26. import lombok.RequiredArgsConstructor;
  27. import lombok.extern.slf4j.Slf4j;
  28. import org.springframework.stereotype.Service;
  29. import javax.imageio.ImageIO;
  30. import java.awt.*;
  31. import java.awt.image.BufferedImage;
  32. import java.io.ByteArrayOutputStream;
  33. import java.io.IOException;
  34. import java.util.List;
  35. import java.util.*;
  36. @Slf4j
  37. @Service
  38. @RequiredArgsConstructor
  39. public class VmsManageService {
  40. private final DebugConfig debug;
  41. private final ApplicationConfig config;
  42. private final VmsManageMapper mapper;
  43. private final AppRepositoryService repoService;
  44. private final VmsFontService fontService;
  45. private final VmsSymbService symbService;
  46. private final VmsFormService formService;
  47. private final VmsIfscService ifscService;
  48. private final VmsAtmpService atmpService;
  49. private final VmsParkService parkService;
  50. private final VwStrmCtlrService vwStrmCtlrService;
  51. private final DbmsDataProcess dbmsDataProcess;
  52. private int toggleFormSeq = 1;
  53. public void initVmsDsplPrst() {
  54. HashMap<String, Object> param = new HashMap<>();
  55. param.put("maxPhase", this.config.getMaxDownloadForms()+1);
  56. this.mapper.initVmsDsplPrst(param);
  57. }
  58. /**
  59. * VMS 기초 정보 로딩
  60. */
  61. public void loadDb() {
  62. Elapsed elapsed = new Elapsed();
  63. log.info("VmsManageService.loadBaseDatabase: START.");
  64. this.fontService.loadDb();
  65. this.vwStrmCtlrService.loadDb();
  66. log.info("VmsManageService.loadBaseDatabase: ..END. {} ms.", elapsed.milliSeconds());
  67. }
  68. /**
  69. * 돌발 및 공사/행사 정보 조회
  70. */
  71. public void loadEventOccrInfo() {
  72. Elapsed elapsed = new Elapsed();
  73. List<TbVmsIncd> result = this.mapper.selectVmsIncd();
  74. result.forEach(data -> {
  75. TbVmsCtlrDto vmsObj = this.repoService.getCtlrMap(data.getVmsCtlrNmbr());
  76. if (vmsObj == null) {
  77. log.error("VmsManageService.loadEventOccrInfo: Not Found VMS {}, Incident {}.", data.getVmsCtlrNmbr(), data.getIncdOcrrId());
  78. return;
  79. }
  80. // if (!vmsObj.isProvide()) {
  81. // log.error("VmsManageService.loadEventOccrInfo: VMS {}, Provide {}.", data.getVmsCtlrNmbr(), vmsObj.isProvide());
  82. // return;
  83. // }
  84. if ("VIT1".equals(data.getVmsIncdTypeCd())) {
  85. // 사고
  86. vmsObj.getIncident().add(data.toDto());
  87. }
  88. else {
  89. // 공사/행사
  90. vmsObj.getEvent().add(data.toDto());
  91. }
  92. });
  93. log.info("VmsManageService.loadEventOccrInfo: {} ms.", elapsed.milliSeconds());
  94. }
  95. /**
  96. * VMS 정보제공구간 정체 판정
  97. */
  98. public void congestJudgment() {
  99. this.repoService.getCtlrMap().forEach((key, obj) -> {
  100. obj.getRltnIfscMap().forEach((ifscId, ifsc) -> {
  101. if (!ifsc.isUsed()) {
  102. return; // 사용안함
  103. }
  104. if (!ifsc.isCngstCnfmYn()) {
  105. return; // 정체판정이 아닌경우
  106. }
  107. TbVmsIfscTrafDto ifscTraf = this.ifscService.find(ifsc.getVmsIfscId());
  108. if (ifscTraf == null) {
  109. log.error("VmsManageService.congestJudgment: VMS {}, Not Found VMS IFSC TRAF {}.", ifsc.getVmsCtlrNmbr(), ifsc.getVmsIfscId());
  110. ifsc.setCngstCnt(0);
  111. return;
  112. }
  113. if (ifsc.getCngstSped() > ifscTraf.getSped()) {
  114. // 현재속도값이 정체판정속도 이하이면 정체판정 횟수를 증가
  115. if (ifsc.getCngstCnt() == 0) {
  116. ifsc.setCngstDt(ItsUtils.getSysTime());
  117. }
  118. // 가공주기에 대해서 정체가 지속되는 경우 주기를 증가
  119. // 연속으로 정체로 판정되는 경우에 한해서 정체폼을 생성하기 위함.
  120. ifsc.setCngstCnt(ifsc.getCngstCnt()+1);
  121. }
  122. else {
  123. // 정체판정속도보다 크면 정체횟수를 초기화
  124. ifsc.setCngstCnt(0);
  125. }
  126. });
  127. });
  128. }
  129. /**
  130. * VMS 교통정보 표출 스케쥴 조회
  131. */
  132. public void loadVmsDsplTrafSchedule(TbVmsCtlrDto vmsObj, TbVmsFormDto vmsForm, TbVmsScheduleDto schedule) {
  133. eVmsFormType vmsFormType = eVmsFormType.getValue(vmsForm.getVmsFormTypeCd());
  134. if (vmsFormType != eVmsFormType.eFormTp_figure) {
  135. // 도형식 소통정보 스케쥴이 아닌 일반 소통정보 스케쥴 인 경우
  136. TbVmsScheduleDto trafSchedule = schedule.clone();
  137. vmsObj.getSchedule().add(trafSchedule);
  138. return;
  139. }
  140. // 도형식 소통정보 스케쥴
  141. boolean isIfscTraf = false;
  142. Long trafIfscId = 0L;
  143. int trafIfscCnt = 0; //전체 표출할 하단 소통정보 갯수
  144. boolean isAxisTraf = false;
  145. Long axisIfscId = 0L;
  146. int trafAxisCnt = 0; //전체 표출할 하단 소통정보 갯수
  147. boolean isTraffic = false;
  148. int missingCnt = 0;
  149. int figureDisplayTm = schedule.getDsplHh();
  150. TbVmsSymbLibDto backTrafSymb = this.symbService.find(vmsForm.getTrfBackImgId()); // 심벌번호+"0"
  151. if (backTrafSymb == null) {
  152. log.error("VmsManageService.loadVmsDsplTrafSchedule: VMS {} Back Traffic Form {}, Not Found Back Traffic Image {}.",
  153. vmsObj.getVmsCtlrNmbr(), vmsForm.getVmsFormId(), vmsForm.getTrfBackImgId());
  154. return;
  155. }
  156. // 배경 이미지에 설정된 구간에 대해서 소통정보 확인
  157. for (Map.Entry<Integer, TbVmsSymbIfscDto> e : backTrafSymb.getCellMap().entrySet()) {
  158. TbVmsSymbIfscDto cell = e.getValue();
  159. if (cell.isDup()) {
  160. continue;
  161. }
  162. TbVmsIfscTrafDto ifscTraf = this.ifscService.find(cell.getVmsIfscId());
  163. if (ifscTraf == null) {
  164. log.error("VmsManageService.loadVmsDsplTrafSchedule: VMS {} Back Traffic Form {}, IFSC Not Found {}, cellId {}.",
  165. vmsObj.getVmsCtlrNmbr(), vmsForm.getVmsFormId(), cell.getVmsIfscId(), cell.getCellId());
  166. missingCnt++;
  167. continue;
  168. }
  169. if (0 == ifscTraf.getCmtrGradCd()) {
  170. missingCnt++;
  171. }
  172. else {
  173. isTraffic = true;
  174. if ("Y".equals(ifscTraf.getAxisYn())) {
  175. // 축 구간
  176. if (axisIfscId == 0L) {
  177. axisIfscId = ifscTraf.getVmsIfscId();
  178. }
  179. if (vmsForm.isBottomTrfAxis()) {
  180. isAxisTraf = true; // 첫번째 소통정보가 표출되도록 함
  181. trafAxisCnt++;
  182. }
  183. }
  184. else {
  185. // 정보제공구간
  186. if (trafIfscId == 0L) {
  187. trafIfscId = cell.getVmsIfscId(); // 지/정체 정보가 없을 경우 하단 소통정보에 표출할 정보제공구간
  188. }
  189. if (vmsForm.isBottomTrfIfsc()) {
  190. if (3 == ifscTraf.getCmtrGradCd() || 2 == ifscTraf.getCmtrGradCd()) {
  191. // 지/정체구간
  192. isIfscTraf = true; // 도형식배경소통정보의 셀내의 구간정보 소통정보가 하나라도 있으면 도형식 소통정보를 표출함
  193. trafIfscCnt++;
  194. }
  195. }
  196. }
  197. }
  198. }
  199. // 민간정보 연계에서 정보가 수집되지 않는 경우 가 종종 있어서 도형식 소통정보를 채우지 못한다.
  200. // 결측구간이 3구간 이상이면 도형식 소통정보 표출하지 말자
  201. // 도형식 구간의 모든 소통정보가 생성되지 않았음===> 가공서버가 죽었거나 수집되지 않았음.
  202. if (!isTraffic || missingCnt >= 3) {
  203. log.error("VmsManageService.loadVmsDsplTrafSchedule: VMS {} Back Traffic Form {}, {}, IFSC Missing Traffic {} EA.",
  204. vmsObj.getVmsCtlrNmbr(), vmsForm.getVmsFormId(), isTraffic, missingCnt);
  205. return;
  206. }
  207. // 하단에 정보제공구간 소통정보를 표출해야 하는 경우
  208. if (vmsForm.isBottomTrfIfsc()) {
  209. // 도형식 하단에 정보제공구간 소통정보 표출하는 경우 다중폼이 생성됨
  210. // 제공구간소통정보가 정체, 지체인 경우만 하단 소통정보를 표출함
  211. // 도형식 배경셀에 등록된 구간에 대해서 표출하도록함
  212. if (trafIfscId != 0L && !isIfscTraf) {
  213. // 소통정보는 존재하지만 지체, 정체가 없는 경우 하단 소통정보를 표출못하게 된다.
  214. // 만일 하단 고정문자가 존재하는 경우 하단 고정문자를 표출하면 되지만
  215. // 고정문자가 존재하기 않으면 하단에 표출할 정보가 없으므로 첫번째 구간의 정보를 표출하도록 한다.
  216. if (!vmsForm.isBottomFixedText()) {
  217. isIfscTraf = true; // 첫번째 소통정보가 표출되도록 함
  218. trafIfscCnt = 1;
  219. }
  220. }
  221. }
  222. // 하단에 VMS 축 소통정보를 표출해야 하는 경우
  223. if (vmsForm.isBottomTrfAxis()) {
  224. // 도형식 소통정보 폼일때 하단에 VMS 축 소통정보를 표출해야 하는 경우 다중폼이 생성됨
  225. // 축 소통정보인 경우 모든 축에 대해 소통정보를 표출, 최대 표출설정값이 설정된 경우 설정값만큼만 표출되게 수정(20200515)
  226. if (axisIfscId != 0L && !isAxisTraf) {
  227. // 하단 축 소통정보가 없는 경우 하단 소통정보를 표출못하게 된다.
  228. // 만일 하단 고정문자가 존재하는 경우 하단 고정문자를 표출하면 되지만
  229. // 고정문자가 존재하기 않으면 하단에 표출할 정보가 없으므로 첫번째 구간의 정보를 표출하도록 한다.
  230. if (!vmsForm.isBottomFixedText()) {
  231. isAxisTraf = true; // 첫번째 소통정보가 표출되도록 함
  232. trafAxisCnt = 1;
  233. }
  234. }
  235. }
  236. if (!isIfscTraf && !isAxisTraf) {
  237. // 하단에 표출할 소통정보가 존재하지 않는 경우
  238. TbVmsScheduleDto trafSchedule = schedule.clone();
  239. trafSchedule.initTrafId();
  240. vmsObj.getSchedule().add(trafSchedule);
  241. return;
  242. }
  243. int fromMaxCnt = 0;
  244. List<Long> ifscIds = new ArrayList<>();
  245. if (isIfscTraf) {
  246. fromMaxCnt = trafIfscCnt;
  247. if (this.config.getBottomTrafficMax() > 0 && trafIfscCnt > this.config.getBottomTrafficMax()) {
  248. fromMaxCnt = this.config.getBottomTrafficMax();
  249. }
  250. if (this.config.getBottomTrafficCycle() > 0) {
  251. int dsplTm = figureDisplayTm / trafIfscCnt;
  252. if (dsplTm < this.config.getBottomTrafficCycle()) {
  253. figureDisplayTm = this.config.getBottomTrafficCycle();
  254. } else {
  255. figureDisplayTm = dsplTm;
  256. }
  257. }
  258. // 정보제공구간 정체정보 표출
  259. for (Map.Entry<Integer, TbVmsSymbIfscDto> e : backTrafSymb.getCellMap().entrySet()) {
  260. TbVmsSymbIfscDto cell = e.getValue();
  261. if (cell.isDup()) {
  262. continue;
  263. }
  264. TbVmsIfscTrafDto ifscTraf = this.ifscService.find(cell.getVmsIfscId());
  265. if (ifscTraf == null || "Y".equals(ifscTraf.getAxisYn())) {
  266. continue;
  267. }
  268. if (3 == ifscTraf.getCmtrGradCd()) {
  269. ifscIds.add(cell.getVmsIfscId());
  270. }
  271. }
  272. // 정보제공구간 지체정보 표출
  273. for (Map.Entry<Integer, TbVmsSymbIfscDto> e : backTrafSymb.getCellMap().entrySet()) {
  274. TbVmsSymbIfscDto cell = e.getValue();
  275. if (cell.isDup()) {
  276. continue;
  277. }
  278. TbVmsIfscTrafDto ifscTraf = this.ifscService.find(cell.getVmsIfscId());
  279. if (ifscTraf == null || "Y".equals(ifscTraf.getAxisYn())) {
  280. continue;
  281. }
  282. if (2 == ifscTraf.getCmtrGradCd()) {
  283. ifscIds.add(cell.getVmsIfscId());
  284. }
  285. }
  286. if (ifscIds.isEmpty() && trafIfscId != 0L && !vmsForm.isBottomFixedText()) {
  287. // 지정체구간이 없고 하단 고정문자가 없으면서 첫번째 정보제공구간 데이터가 존재하는 경우
  288. ifscIds.add(trafIfscId);
  289. }
  290. }
  291. if (isAxisTraf) {
  292. fromMaxCnt = trafAxisCnt;
  293. if (this.config.getBottomTrafficCycle() > 0) {
  294. int dsplTm = figureDisplayTm / trafAxisCnt;
  295. if (dsplTm < this.config.getBottomTrafficCycle()) {
  296. figureDisplayTm = this.config.getBottomTrafficCycle();
  297. } else {
  298. figureDisplayTm = dsplTm;
  299. }
  300. }
  301. // 축 소통정보 표출
  302. for (Map.Entry<Integer, TbVmsSymbIfscDto> e : backTrafSymb.getCellMap().entrySet()) {
  303. TbVmsSymbIfscDto cell = e.getValue();
  304. if (cell.isDup()) {
  305. continue;
  306. }
  307. TbVmsIfscTrafDto ifscTraf = this.ifscService.find(cell.getVmsIfscId());
  308. if (ifscTraf == null || !"Y".equals(ifscTraf.getAxisYn())) {
  309. continue;
  310. }
  311. if (0 != ifscTraf.getCmtrGradCd()) {
  312. ifscIds.add(cell.getVmsIfscId());
  313. }
  314. }
  315. if (ifscIds.isEmpty() && axisIfscId != 0L && !vmsForm.isBottomFixedText()) {
  316. // 지정체구간이 없고 하단 고정문자가 없으면서 첫번째 정보제공구간 데이터가 존재하는 경우
  317. ifscIds.add(axisIfscId);
  318. }
  319. }
  320. if (ifscIds.isEmpty()) {
  321. // 하단에 표출할 정보가 없는 경우
  322. TbVmsScheduleDto trafSchedule = schedule.clone();
  323. trafSchedule.initTrafId();
  324. vmsObj.getSchedule().add(trafSchedule);
  325. }
  326. else {
  327. for (int ii = 0; ii < ifscIds.size() && ii < fromMaxCnt; ii++) {
  328. TbVmsScheduleDto trafSchedule = schedule.clone();
  329. trafSchedule.setDnldFormId(schedule.getDnldFormId()+ii);
  330. trafSchedule.initTrafId();
  331. trafSchedule.setVmsIfscId(ifscIds.get(ii));
  332. trafSchedule.setFrstVmsIfscId(ifscIds.get(ii));
  333. trafSchedule.setDsplHh(figureDisplayTm);
  334. vmsObj.getSchedule().add(trafSchedule);
  335. }
  336. }
  337. }
  338. /**
  339. * VMS 표출 스케쥴 정보를 조회
  340. */
  341. public void loadVmsDsplSchedule() {
  342. Elapsed elapsed = new Elapsed();
  343. List<TbVmsSchedule> result = this.mapper.selectVmsDsplSchedule();
  344. result.forEach(data -> {
  345. TbVmsCtlrDto vmsObj = this.repoService.getCtlrMap(data.getVmsCtlrNmbr());
  346. if (vmsObj == null) {
  347. log.error("VmsManageService.loadVmsDsplSchedule: Not Found VMS {}, Schedule Phase {}.", data.getVmsCtlrNmbr(), data.getPhase());
  348. return;
  349. }
  350. TbVmsFormDto vmsForm = this.formService.find(data.getVmsFormId());
  351. if (vmsForm == null) {
  352. log.error("VmsManageService.loadVmsDsplSchedule: VMS {}, Not Found Form {}.", data.getVmsCtlrNmbr(), data.getVmsFormId());
  353. return;
  354. }
  355. eVmsScheduleType vmsSchFormType = eVmsScheduleType.getValue(data.getVmsSchFormType());
  356. if (vmsSchFormType == null) {
  357. log.error("VmsManageService.loadVmsDsplSchedule: Unknown Form Schedule Type: VMS({}), FormId({}), FormScheduleType({})",
  358. data.getVmsCtlrNmbr(), data.getVmsFormId(), data.getVmsSchFormType());
  359. return;
  360. }
  361. eVmsFormType vmsFormType = eVmsFormType.getValue(vmsForm.getVmsFormTypeCd());
  362. if (vmsFormType == null) {
  363. log.error("VmsManageService.loadVmsDsplSchedule: Unknown Form Type: VMS({}), FormId({}), FormScheduleType({})",
  364. data.getVmsCtlrNmbr(), data.getVmsFormId(), vmsForm.getVmsFormTypeCd());
  365. return;
  366. }
  367. // 조회정렬은 기본,고정,자동(돌발,공사,행사,우회,교통,정체폼) 순으로 조회된다.
  368. // 따라서 각 폼에 대한처리를 수행하면 된다.
  369. // ==> 신규작업에서 폼 표출 우선순위적용함 ==> 조회정렬이 영향이 있는지 확인해야함.
  370. // eFormTp_traf_1 = 11, // 소통상황(1단)
  371. // eFormTp_traf_2 = 12, // 소통상황(2단)
  372. // eFormTp_traf_3 = 13, // 소통상황(3단)
  373. // eFormTp_traf_4 = 14, // 소통상황(4단)
  374. boolean isIncidentForm = false;
  375. if (vmsSchFormType == eVmsScheduleType.eSchTp_traffic && vmsFormType == eVmsFormType.eFormTp_traf_1) {
  376. // 교통정보스케쥴이고 폼의 유형이 소통정보(1단) 인경우
  377. // 해당 폼이 돌발이나 이벤트가 등록되어 있다면 폼을 생성하지 않는다.
  378. Long frstVmsIfscId = data.getFrstVmsIfscId();
  379. if (frstVmsIfscId != null && frstVmsIfscId != 0L) {
  380. for (int ii = 0; ii < vmsObj.getSchedule().getUnits().size(); ii++) {
  381. TbVmsScheduleDto schedule = vmsObj.getSchedule().getUnits().get(ii);
  382. eVmsScheduleType scheduleFormType = eVmsScheduleType.getValue(schedule.getVmsSchFormType());
  383. if (scheduleFormType == eVmsScheduleType.eSchTp_incident || //돌발
  384. scheduleFormType == eVmsScheduleType.eSchTp_gongsa || //공사/행사
  385. scheduleFormType == eVmsScheduleType.eSchTp_deture //우회도로
  386. ) {
  387. if (schedule.getEvent() != null && Objects.equals(schedule.getEvent().getVmsIfscId(), frstVmsIfscId)) {
  388. isIncidentForm = true;
  389. break;
  390. }
  391. }
  392. }
  393. }
  394. }
  395. if (isIncidentForm) {
  396. log.error("VmsManageService.loadVmsDsplSchedule: VMS {}, Form {}, IFSC ID {} Incident Occurred.",
  397. vmsObj.getVmsCtlrNmbr(), vmsForm.getVmsFormId(), data.getFrstVmsIfscId());
  398. return;
  399. }
  400. final int[] formIdx = new int[1];
  401. TbVmsScheduleDto schedule = data.toDto();
  402. switch(vmsSchFormType) {
  403. case eSchTp_traffic: // 교통정보
  404. loadVmsDsplTrafSchedule(vmsObj, vmsForm, schedule);
  405. break;
  406. case eSchTp_incident: // 돌발
  407. // 돌발 스케줄인 경우 해당 VMS 에 발생한 모든 돌발 정보를 표출하도록 스케줄 추가
  408. formIdx[0] = 0;
  409. vmsObj.getIncident().getUnits().forEach(incd -> {
  410. TbVmsScheduleDto incdSchedule = schedule.clone();
  411. incdSchedule.setDnldFormId(schedule.getDnldFormId() + formIdx[0]++);
  412. incdSchedule.setVmsIfscId(incd.getVmsIfscId());
  413. incdSchedule.setEvent(incd);
  414. vmsObj.getSchedule().add(incdSchedule);
  415. });
  416. break;
  417. case eSchTp_gongsa: // 공사/행사문안
  418. // 공사/행사 스케줄인 경우 해당 VMS 에 발생한 모든 돌발 정보를 표출하도록 스케줄 추가
  419. formIdx[0] = 0;
  420. vmsObj.getEvent().getUnits().forEach(event -> {
  421. TbVmsScheduleDto eventSchedule = schedule.clone();
  422. eventSchedule.setDnldFormId(schedule.getDnldFormId() + formIdx[0]++);
  423. eventSchedule.setVmsIfscId(event.getVmsIfscId());
  424. eventSchedule.setEvent(event);
  425. vmsObj.getSchedule().add(eventSchedule);
  426. });
  427. break;
  428. case eSchTp_hongbo: // 홍보
  429. TbVmsScheduleDto hongboSchedule = schedule.clone();
  430. vmsObj.getSchedule().add(hongboSchedule);
  431. break;
  432. case eSchTp_deture: // 우회도로
  433. // 돌발발생한 구간중 우회도로 구간이 있는경우
  434. formIdx[0] = 0;
  435. vmsObj.getIncident().getUnits().forEach(incd -> {
  436. if (incd.getDetrId() == 0L || incd.getVmsIfscId() == 0) {
  437. return;
  438. }
  439. TbVmsScheduleDto detureSchedule1 = schedule.clone();
  440. detureSchedule1.setDnldFormId(schedule.getDnldFormId() + formIdx[0]++);
  441. detureSchedule1.setVmsIfscId(incd.getVmsIfscId());
  442. detureSchedule1.setEvent(incd);
  443. vmsObj.getSchedule().add(detureSchedule1);
  444. });
  445. // 공사/행사 발생한 구간중 우회도로 구간이 있는경우
  446. vmsObj.getEvent().getUnits().forEach(event -> {
  447. if (event.getDetrId() == 0L || event.getVmsIfscId() == 0) {
  448. return;
  449. }
  450. TbVmsScheduleDto detureSchedule2 = schedule.clone();
  451. detureSchedule2.setDnldFormId(schedule.getDnldFormId() + formIdx[0]++);
  452. detureSchedule2.setVmsIfscId(event.getVmsIfscId());
  453. detureSchedule2.setEvent(event);
  454. vmsObj.getSchedule().add(detureSchedule2);
  455. });
  456. break;
  457. case eSchTp_congest: // 정체상황
  458. formIdx[0] = 0;
  459. vmsObj.getRltnIfscMap().forEach((key, cngs) -> {
  460. if (!cngs.isUsed() || !cngs.isCngstCnfmYn()) {
  461. // 정체판정이 아닌경우
  462. return;
  463. }
  464. if (cngs.getCngstCnt() < this.config.getCngstContCount()) {
  465. // 설정되어 있는 정체판정 횟수보다 작으면 정체아님. 정체가 연속에서 반복되는 최소 갯수임...
  466. return;
  467. }
  468. if (vmsObj.getCngstForms() < vmsObj.getMaxCngstForm()) {
  469. vmsObj.setCngstForms(cngs.getCngstCnt()+1);
  470. vmsObj.setExistCngsForm(true);
  471. TbVmsScheduleDto congestSchedule = schedule.clone();
  472. congestSchedule.setDnldFormId(schedule.getDnldFormId() + formIdx[0]++);
  473. congestSchedule.setFrstVmsIfscId(cngs.getVmsIfscId());
  474. congestSchedule.setVmsIfscId(cngs.getVmsIfscId());
  475. vmsObj.getSchedule().add(congestSchedule);
  476. }
  477. });
  478. break;
  479. case eSchTp_video: //동영상
  480. // 동영상명칭이 설정되지 않은 것은 표출하지 않는다.
  481. //if (data.getSymbLibNmbr() != 0 && data.getSymbLibNmbr() != 200 && !"".equals(data.getStrmAddr()))
  482. {
  483. TbVmsScheduleDto videoSchedule = schedule.clone();
  484. vmsObj.getSchedule().add(videoSchedule);
  485. }
  486. break;
  487. case eSchTp_stream: //스트리밍영상
  488. //스트리밍주소가 설정되지 않은 것은 표출하지 않는다.
  489. //if (data.getSymbLibNmbr() == 300 && !"".equals(data.getStrmAddr()))
  490. {
  491. TbVmsScheduleDto streamSchedule = schedule.clone();
  492. vmsObj.getSchedule().add(streamSchedule);
  493. }
  494. break;
  495. case eSchTp_atmp: //9:대기환경
  496. Long atmpSttnNmbr = 0L;
  497. boolean isAtmp = false;
  498. for (int ii = 0; ii < vmsForm.getObjects().size(); ii++) {
  499. TbVmsFormObjectDto tmpFormObj = vmsForm.getObjects().get(ii);
  500. /**
  501. 90 401 @관측장소 Y
  502. 90 402 @PM10 Y
  503. 90 403 @PM2.5 Y
  504. 90 404 @PM10등급 Y
  505. 90 405 @PM2.5등급 Y
  506. 90 406 @통합대기등급 이미지 Y
  507. 90 407 @미세먼지등급 이미지 Y
  508. 90 408 @초미세먼지등급 이미지 Y
  509. 90 409 @통합대기등급 Y
  510. 90 410 @통합대기 Y
  511. 90 411 @오존 Y
  512. 90 412 @오존등급 Y
  513. 90 413 @오존등급이미지 Y
  514. */
  515. if (tmpFormObj.getVmsFormObjectTypeCd() >= 401 && tmpFormObj.getVmsFormObjectTypeCd() <= 413) {
  516. atmpSttnNmbr = tmpFormObj.getVmsIfscId();
  517. TbVmsAtmpDto atmpObj = this.atmpService.find(atmpSttnNmbr);
  518. if (atmpObj == null) {
  519. log.error("VmsManageService.loadVmsDsplSchedule: VMS {}, ATMP Form {}, Not Found AtmpSttnNmb {}.",
  520. vmsObj.getVmsCtlrNmbr(), vmsForm.getVmsFormId(), atmpSttnNmbr);
  521. continue;
  522. }
  523. if (atmpObj.isSuccess()) {
  524. isAtmp = true;
  525. break;
  526. }
  527. }
  528. }
  529. if (isAtmp) {
  530. TbVmsScheduleDto atmpSchedule = schedule.clone();
  531. atmpSchedule.setFrstVmsIfscId(atmpSttnNmbr);
  532. vmsObj.getSchedule().add(atmpSchedule);
  533. }
  534. else {
  535. log.error("VmsManageService.loadVmsDsplSchedule: VMS {}, ATMP Form {}, Atmp Traffic Failed.",
  536. vmsObj.getVmsCtlrNmbr(), vmsForm.getVmsFormId());
  537. }
  538. break;
  539. case eSchTp_park: //10:주차정보
  540. boolean isParkingForm = false;
  541. for (int ii = 0; ii < vmsForm.getObjects().size(); ii++) {
  542. TbVmsFormObjectDto tmpFormObj = vmsForm.getObjects().get(ii);
  543. /**
  544. 100 101 @주차장명 N
  545. 100 102 @주차면수 Y
  546. 100 103 @주차가능면수 Y
  547. 100 104 @주차혼잡도 Y
  548. */
  549. if (tmpFormObj.getVmsFormObjectTypeCd() >= 101 && tmpFormObj.getVmsFormObjectTypeCd() <= 104) {
  550. TbVmsParkDto parkObj = this.parkService.find(tmpFormObj.getVmsIfscId());
  551. if (parkObj == null) {
  552. log.error("VmsManageService.loadVmsDsplSchedule: VMS {}, Parking Form {}, Not Found Parking {}.",
  553. vmsObj.getVmsCtlrNmbr(), vmsForm.getVmsFormId(), tmpFormObj.getVmsIfscId());
  554. continue;
  555. }
  556. if (parkObj.isSuccess()) {
  557. isParkingForm = true;
  558. break;
  559. }
  560. }
  561. }
  562. if (isParkingForm) {
  563. TbVmsScheduleDto parkSchedule = schedule.clone();
  564. vmsObj.getSchedule().add(parkSchedule);
  565. }
  566. else {
  567. log.error("VmsManageService.loadVmsDsplSchedule: VMS {}, Parking Form {}, Parking Congest Failed.",
  568. vmsObj.getVmsCtlrNmbr(), vmsForm.getVmsFormId());
  569. }
  570. break;
  571. case eSchTp_evehicle: //11:긴급차량우선신호
  572. if (vmsForm.getVmsFormDsplDrctCd() == 0) {
  573. vmsObj.setEvehIngForm(true);
  574. }
  575. else {
  576. vmsObj.setEvehEndForm(true);
  577. schedule.setDsplHh(60);
  578. }
  579. TbVmsScheduleDto evehSchedule = schedule.clone();
  580. vmsObj.getSchedule().add(evehSchedule);
  581. break;
  582. default:
  583. break;
  584. }
  585. });
  586. log.info("VmsManageService.loadVmsDsplSchedule: {} ms.", elapsed.milliSeconds());
  587. }
  588. /**
  589. * VMS 운영모드 정보 조회
  590. */
  591. public void loadVmsOperationMode() {
  592. Elapsed elapsed = new Elapsed();
  593. List<TbVmsOperMode> result = this.mapper.selectVmsOperMode();
  594. result.forEach(data-> {
  595. TbVmsCtlrDto vmsObj = this.repoService.getCtlrMap(data.getVmsCtlrNmbr());
  596. if (vmsObj == null) {
  597. log.error("VmsManageService.loadVmsOperationMode: Not Found VMS {}.", data.getVmsCtlrNmbr());
  598. return;
  599. }
  600. if (!"A".equals(data.getOperMode()) && !"F".equals(data.getOperMode()) && !"B".equals(data.getOperMode())) {
  601. data.setOperMode("A");
  602. }
  603. String oldOperMode = vmsObj.getOperMode();
  604. vmsObj.setOperMode(data.getOperMode());
  605. vmsObj.setMaxPhaseNum(Math.min(this.config.getMaxDownloadForms(), data.getVmsMaxPhaseNum()));
  606. // VMS 별 정체폼갯수를 제한하는 경우 여기에서 처리하도록 하자
  607. vmsObj.setMaxCngstForm(Math.min(this.config.getMaxCngstForms(), VmsConstants.VMS_MAX_CNGS_FORM));
  608. if (data.getOperMode().equals(oldOperMode)) {
  609. // TODO: 화면 업데이트
  610. }
  611. });
  612. log.info("VmsManageService.loadVmsOperationMode: {} ms.", elapsed.milliSeconds());
  613. }
  614. public void initProvide(TbVmsCtlrDto AObj) {
  615. this.repoService.getCtlrMap().forEach((key, obj) -> {
  616. if (AObj == null || obj.getVmsCtlrNmbr() == AObj.getVmsCtlrNmbr()) {
  617. obj.setProvide(true);
  618. }
  619. });
  620. }
  621. public void clearVmsProvideMode() {
  622. String dsplDt = ItsUtils.getSysTime();
  623. this.repoService.getCtlrMap().forEach((key, obj) -> {
  624. obj.getEvechile().getUnits().clear();
  625. obj.setEvehIngForm(false);
  626. obj.setEvehEndForm(false);
  627. obj.getSchedule().getUnits().clear();
  628. obj.getIncident().getUnits().clear();
  629. obj.getEvent().getUnits().clear();
  630. obj.getFormManager().clear();
  631. obj.setCngstForms(0);
  632. obj.setMaxCngstForm(this.config.getMaxCngstForms());
  633. obj.setExistCngsForm(false);
  634. // if (!obj.isProvide()) {
  635. // return;
  636. // }
  637. obj.getControlMode().setMaxDisplayForm(0);
  638. obj.getControlMode().setEnable(false);
  639. obj.getControlMode().setSvcDate(dsplDt);
  640. obj.getControlMode().setSaveFlag(true);
  641. obj.getControlMode().setTimer(System.currentTimeMillis());
  642. obj.getControlMode().setResult(false);
  643. });
  644. }
  645. /**
  646. * VMS 다운로드 폼 정보 생성
  647. */
  648. public void jobMakeDownloadVmsForm() {
  649. log.info("VmsManageService.jobMakeDownloadVmsForm: START.");
  650. Elapsed elapsed = new Elapsed();
  651. if (this.repoService.isStaticCycle()) {
  652. loadVmsOperationMode(); // 운영모드 조회
  653. initProvide(null);
  654. }
  655. clearVmsProvideMode();
  656. makeVmsScenarioForm(); // 시나리오정보 로딩
  657. makeVmsProvideForm(); // 시나리오에 따른 폼 정보 생성
  658. makeVmsDatabaseForm(); // 폼 이미지 생성
  659. /**
  660. * 데이터베이스 처리 프로세스로 VMS 폼 다운로드 정보를 보낸다.
  661. * 데이터베이스 처리 프로레스에서 제어기의 네트워크 상태에 따라서 통신 정상인 제어기로 데이터를 전송한다.
  662. */
  663. this.repoService.setDsplDt(ItsUtils.getSysTime());
  664. this.dbmsDataProcess.add(new DbmsData(DbmsDataType.DBMS_DATA_VMS_FORM_DOWNLOAD, this.repoService.isStaticCycle(), this.repoService.getDsplDt()));
  665. log.info("VmsManageService.jobMakeDownloadVmsForm: {} ms.", elapsed.milliSeconds());
  666. }
  667. /**
  668. * VMS FORM 데이터를 생성한다.
  669. */
  670. public void makeVmsScenarioForm() {
  671. log.info("VmsManageService.makeVmsScenarioForm: START.");
  672. Elapsed elapsed = new Elapsed();
  673. if (this.config.isLoadDb()) {
  674. loadDb();
  675. }
  676. this.symbService.loadDb();
  677. this.formService.loadDb();
  678. this.atmpService.loadDb(); // 기상정보
  679. if (this.config.isUseParking()) {
  680. this.parkService.loadDb(); // 주차정보
  681. }
  682. loadEventOccrInfo(); // 돌발정보조회
  683. this.ifscService.loadDb(); // VMS 정보제공구간 교통정보
  684. if (this.repoService.isStaticCycle()) {
  685. // 정주기 가공일때 처리해야 함
  686. congestJudgment(); // 정체판정
  687. this.repoService.setStaticCycle(false);
  688. }
  689. loadVmsDsplSchedule();
  690. log.info("VmsManageService.makeVmsScenarioForm: {} ms.", elapsed.milliSeconds());
  691. }
  692. public void makeVmsProvideForm() {
  693. log.info("VmsManageService.makeVmsProvideForm: START.");
  694. Elapsed elapsed = new Elapsed();
  695. this.repoService.getCtlrMap().forEach((ctlrNmbr, vmsObj) -> {
  696. if ("Y".equals(vmsObj.getDelYn())) {
  697. return;
  698. }
  699. VmsSchedule scheObj = vmsObj.getSchedule();
  700. int downLoadForms = Math.min(vmsObj.getMaxPhaseNum(), scheObj.size());
  701. vmsObj.getControlMode().setMaxDisplayForm(downLoadForms);
  702. this.config.makeDirectory(vmsObj.getLocalFormDir(), "VMS " + vmsObj.getVmsCtlrNmbr() + " Directory.");
  703. boolean isEVehIngForm = vmsObj.isEvehIngForm() && vmsObj.getEvechile().isOcrr(); // 폼이 존재하고 데이터 발생
  704. boolean isEVehEndForm = vmsObj.isEvehEndForm() && vmsObj.getEvechile().isEnd(); // 폼이 존재하고 데이터 발생
  705. for (int scheduleIdx = 0; scheduleIdx < scheObj.size(); scheduleIdx++) {
  706. TbVmsScheduleDto schedule = scheObj.getUnits().get(scheduleIdx);
  707. if (vmsObj.isExistCngsForm() && !schedule.isDsplCngsYn()) {
  708. // 해당 제어기에 정체폼이 존재하는 경우 스케쥴 폼이 정체일때 표출하지 않는 경우 폼을 생성하지 않는다.
  709. log.info("VmsManageService.makeVmsProvideForm: VMS {}, Congest continuous {}/{}.", ctlrNmbr, vmsObj.isExistCngsForm(), schedule.isDsplCngsYn());
  710. continue;
  711. }
  712. TbVmsFormDto vmsForm = this.formService.find(schedule.getVmsFormId());
  713. if (vmsForm == null) {
  714. log.error("VmsManageService.makeVmsProvideForm: VMS {}, Not Found Form {}.", ctlrNmbr, schedule.getVmsFormId());
  715. continue;
  716. }
  717. eVmsScheduleType vmsSchFormType = eVmsScheduleType.getValue(schedule.getVmsSchFormType());
  718. if (vmsSchFormType == null) {
  719. log.error("VmsManageService.makeVmsProvideForm: Unknown Form Schedule Type: VMS({}), FormId({}), FormScheduleType({})",
  720. ctlrNmbr, schedule.getVmsFormId(), schedule.getVmsSchFormType());
  721. continue;
  722. }
  723. eVmsFormType vmsFormType = eVmsFormType.getValue(vmsForm.getVmsFormTypeCd());
  724. if (vmsFormType == null) {
  725. log.error("VmsManageService.makeVmsProvideForm: Unknown Form Type: VMS({}), FormId({}), FormScheduleType({})",
  726. ctlrNmbr, schedule.getVmsFormId(), vmsForm.getVmsFormTypeCd());
  727. continue;
  728. }
  729. if (isEVehIngForm) {
  730. // 긴급차량 진행중 메시지 표출
  731. if (vmsSchFormType != eVmsScheduleType.eSchTp_evehicle || vmsForm.getVmsFormDsplDrctCd() != 0) {
  732. // 긴급차량우선신호 진행중 일때 스케쥴 유형 및 폼유형이 맞지 않으면 리턴
  733. // 단일 메시지로 표출하는 경우
  734. // log.info("VmsManageService.makeVmsProvideForm: VMS {}, FORM {}, EVehicle Ing {}. {} DsplDrctCd {}.",
  735. // ctlrNmbr, vmsForm.getVmsFormId(), isEVehIngForm, vmsSchFormType, vmsForm.getVmsFormDsplDrctCd());
  736. continue;
  737. }
  738. } else {
  739. if (vmsSchFormType == eVmsScheduleType.eSchTp_evehicle && vmsForm.getVmsFormDsplDrctCd() == 0) {
  740. // log.info("VmsManageService.makeVmsProvideForm: VMS {}, FORM {}, EVehicle Ing {}. {} DsplDrctCd {}.",
  741. // ctlrNmbr, vmsForm.getVmsFormId(), isEVehIngForm, vmsSchFormType, vmsForm.getVmsFormDsplDrctCd());
  742. continue;
  743. }
  744. }
  745. if (isEVehEndForm) {
  746. // 긴급차량 운영종료 메시지 표출
  747. // 운영종료 메시지는 기타 메시지와 같이 내려보낸다. 단, 표출시간을 60초로 해서 내려보내자.
  748. // if (vmsSchFormType != eVmsScheduleType.eSchTp_evehicle || vmsForm.getVmsFormDsplDrctCd() != 1) {
  749. // // 긴급차량우선신호 운영종료 일때 스케쥴 유형 및 폼유형이 맞지 않으면 리턴
  750. // // 단일메시지로 표출하는 경우
  751. // continue;
  752. // }
  753. } else {
  754. if (vmsSchFormType == eVmsScheduleType.eSchTp_evehicle && vmsForm.getVmsFormDsplDrctCd() == 1) {
  755. // log.info("VmsManageService.makeVmsProvideForm: VMS {}, FORM {}, EVehicle End {}. {} DsplDrctCd {}.",
  756. // ctlrNmbr, vmsForm.getVmsFormId(), isEVehEndForm, vmsSchFormType, vmsForm.getVmsFormDsplDrctCd());
  757. continue;
  758. }
  759. }
  760. // 소통정보 표출폼 인 경우 표출할 구간의 소통정보가 존재하지 않는 경우 폼을 생성하지 않도록 한다.
  761. int reqTraffic = 0;
  762. int setTraffic = 0;
  763. switch (vmsFormType) {
  764. case eFormTp_traf_1: reqTraffic = 1; break; // = 11, // 소통상황(1단)
  765. case eFormTp_traf_2: reqTraffic = 2; break; // = 12, // 소통상황(2단)
  766. case eFormTp_traf_3: reqTraffic = 3; break; // = 13, // 소통상황(3단)
  767. case eFormTp_traf_4: reqTraffic = 4; break; // = 14, // 소통상황(4단)
  768. default: break;
  769. }
  770. if (reqTraffic > 0) {
  771. int ss;
  772. Long[] vmsIfscId = { schedule.getFrstVmsIfscId(), schedule.getSecdVmsIfscId(), schedule.getThirVmsIfscId(), schedule.getFourVmsIfscId() };
  773. Long[] imgIfscId = { schedule.getFrstImgIfscId(), schedule.getSecdImgIfscId(), schedule.getThirImgIfscId(), schedule.getFourImgIfscId() };
  774. for (ss = 0; ss < 4; ss++) {
  775. if (vmsIfscId[ss] == 0L) {
  776. vmsIfscId[ss] = imgIfscId[ss];
  777. }
  778. if (vmsIfscId[ss] != 0L) {
  779. setTraffic++;
  780. }
  781. }
  782. if (setTraffic != 0 && (reqTraffic > setTraffic)) {
  783. //실제 소통정보 폼 갯수보다 할당된 구간이 적은 경우에 해당함
  784. reqTraffic = setTraffic;
  785. }
  786. setTraffic = 0;
  787. for (ss = 0; ss < 4; ss++) {
  788. if (vmsIfscId[ss] == 0L) continue;
  789. TbVmsIfscTrafDto ifscTraf = this.ifscService.find(vmsIfscId[ss]);
  790. if (ifscTraf != null && 0 != ifscTraf.getCmtrGradCd()) {
  791. setTraffic++;
  792. }
  793. }
  794. if (reqTraffic != setTraffic) {
  795. log.error("VmsManageService.makeVmsProvideForm: No Traffic: VMS({}), FormId({}), Req {}, Set {}.",
  796. ctlrNmbr, schedule.getVmsFormId(), reqTraffic, setTraffic);
  797. continue;
  798. }
  799. } // 1,2,3,4 단 소통정보 표출 폼인 경우
  800. // 스케줄에 따른 VMS FORM 을 생성한다.
  801. VmsForm form = vmsObj.getFormManager().addForm(schedule.getVmsFormId(), schedule.getDnldFormId());
  802. form.initDownload(vmsObj, vmsForm, schedule);
  803. String videoFileName = "";
  804. String strmAddrNm = "";
  805. for (int objectIdx = 0; objectIdx < vmsForm.getObjects().size(); objectIdx++) {
  806. if (objectIdx >= VmsConstants.VMS_MAX_FORM_OBJECTS) {
  807. log.error("VmsManageService.makeVmsProvideForm: VMS({}), FormId({}), Form Object count overflow {} EA.",
  808. ctlrNmbr, schedule.getVmsFormId(), vmsForm.getObjects().size());
  809. break;
  810. }
  811. TbVmsFormObjectDto obj = vmsForm.getObjects().get(objectIdx);
  812. if (vmsFormType == eVmsFormType.eFormTp_figure) {
  813. // 도형식 배경소통정보 폼인 경우 하단에 표출할 정보가 없는 경우 하단 소통정보 객체는 생성하지 않도록 하자.
  814. switch(obj.getVmsFormObjectTypeCd()) {
  815. case 0: //문자열
  816. case 1: //심볼
  817. case 2: //이미지
  818. //N:일반(모두표출하는것)
  819. //T:소통정보(소통정보가 있는 경우에만 표출하는것)
  820. //F:하단고정(소통정보가 없는 경우에만 표출하는것)
  821. if (schedule.getVmsIfscId() == 0L) {
  822. // 표출할 소통정보가 없는 경우 교통정보 표출인 경우 하단정보 생성하지 않음
  823. if ("T".equals(obj.getTrfcFillCd())) {
  824. continue;
  825. }
  826. }
  827. else {
  828. // 표출할 소통정보가 있는 경우 고정문자 표출인 경우 하단정보 생성하지 않음
  829. if ("F".equals(obj.getTrfcFillCd())) {
  830. continue;
  831. }
  832. }
  833. break;
  834. case 11: case 12: case 13: case 14: case 15: case 16: case 17: case 18: case 19:
  835. if (schedule.getVmsIfscId() == 0L) {
  836. continue; //하단에 표출할 정보제공구간이 없는 경우임
  837. }
  838. if (obj.getVmsFormObjectTypeCd() == 17) {
  839. // 하단 소통정보이미지
  840. schedule.setFrstImgIfscId(schedule.getVmsIfscId());
  841. }
  842. break;
  843. default: break;
  844. }
  845. } // (vmsFormType == eVmsFormType.eFormTp_figure)
  846. VmsFormObject formObj = form.addFormObject(obj.getVmsFormObjectId());
  847. formObj.setFormObjectInfo(this.fontService.getFontName(obj.getVmsFontNameCd()), obj);
  848. if (formObj.getBlinking() == 1) {
  849. // 객체 Blinking 정보가 다운로드 될때 폼정보로 다운로드 되지 않기 때문에
  850. // Blinking 하기 위해서는 객체로 다운로드 하여야 한다.
  851. form.setObjectDownload(true);
  852. form.setVmsFormDsplDrctCd(1);
  853. }
  854. if (obj.getVmsFormObjectTypeCd() == 200 || obj.getVmsFormObjectTypeCd() == 300) {
  855. // 200:동영상이미지, 300:스트리밍영상이미지
  856. if (obj.getVmsFormObjectTypeCd() == 200) {
  857. formObj.setVideoFileName(obj.getVideoFileName());
  858. formObj.setTextData(obj.getVideoFileName());
  859. videoFileName = formObj.getTextData();
  860. }
  861. else if (obj.getVmsFormObjectTypeCd() == 300) {
  862. formObj.setStrmAddr(obj.getStrmAddr());
  863. formObj.setTextData(obj.getStrmCtlrNm());
  864. //formObj.setTextData(obj.getStrmAddr());
  865. strmAddrNm = formObj.getTextData();
  866. }
  867. form.setObjectDownload(true);
  868. formObj.setMemSymbLibNmbr(obj.getSymbLibNmbr()+"0");
  869. //if (obj.getVmsFormObjectTypeCd() == 200)
  870. {
  871. if (formObj.getDsplWidth() == 0 || formObj.getDsplHeight() == 0) {
  872. formObj.setPosX(0); // NUMBER(5) Y VMS 표출 X좌표
  873. formObj.setPosY(0); // NUMBER(5) Y VMS 표출 Y좌표
  874. formObj.setDsplWidth(form.getWidth()); // NUMBER(5) Y 0 VMS 표출 넓이
  875. formObj.setDsplHeight(form.getHeight());// NUMBER(5) Y 0 VMS 표출 높이
  876. }
  877. TbVmsSymbLibDto symb = this.symbService.find(formObj.getMemSymbLibNmbr());
  878. if (symb == null) {
  879. log.error("VmsManageService.makeVmsProvideForm: VMS({}), FormId({}), Form Object Video Symbol Not Found {}.",
  880. ctlrNmbr, schedule.getVmsFormId(), formObj.getMemSymbLibNmbr());
  881. }
  882. else {
  883. if (form.getDsplHh() == 0 || form.getDsplHh() > symb.getPlayTm()) {
  884. if (symb.getPlayTm() > 0) {
  885. form.setDsplHh(Math.toIntExact(symb.getPlayTm()));
  886. }
  887. }
  888. }
  889. }
  890. }
  891. if (formObj.getObjectKind() != eVmsFormObjectKind.OBJECT_TEXT) {
  892. if (obj.getVmsFormObjectTypeCd() == 200 || obj.getVmsFormObjectTypeCd() == 300) {
  893. // 200:동영상이미지, 300:스트리밍영상이미지
  894. TbVmsSymbLibDto symb = this.symbService.find(formObj.getMemSymbLibNmbr());
  895. if (symb != null) {
  896. formObj.setImageData(symb.getImageData());
  897. }
  898. else {
  899. formObj.setImageData(formObj.getImageData());
  900. log.error("VmsManageService.makeVmsProvideForm: VMS({}), FormId({}), Symbol Not Found {} set form object image data.",
  901. ctlrNmbr, schedule.getVmsFormId(), formObj.getMemSymbLibNmbr());
  902. }
  903. }
  904. else if (obj.getVmsFormObjectTypeCd() == 406 || //@통합대기등급 이미지
  905. obj.getVmsFormObjectTypeCd() == 407 || //@미세먼지등급 이미지
  906. obj.getVmsFormObjectTypeCd() == 408 || //@초미세먼지등급 이미지
  907. obj.getVmsFormObjectTypeCd() == 413 ) //@오존등급이미지
  908. {
  909. TbVmsAtmpDto atmp = this.atmpService.find(obj.getVmsIfscId());
  910. if (atmp != null && atmp.isSuccess()) {
  911. // 관측장소 정보가 존재하는 경우에만 대기환경이미지를 폼에 적용한다.
  912. int atmpGrad = 0;
  913. switch(obj.getVmsFormObjectTypeCd())
  914. {
  915. case 406: atmpGrad = ItsUtils.parseIntDef(atmp.getIntgAtmpGrad(), 1); break;
  916. case 407: atmpGrad = ItsUtils.parseIntDef(atmp.getPm101hhGrad(), 1); break;
  917. case 408: atmpGrad = ItsUtils.parseIntDef(atmp.getPm251hhGrad(), 1); break;
  918. case 413: atmpGrad = ItsUtils.parseIntDef(atmp.getO3Grad(), 1); break;
  919. }
  920. if (atmpGrad > 0) {
  921. atmpGrad--;
  922. }
  923. TbVmsSymbLibDto symb = this.symbService.find(formObj.getMemSymbLibNmbr());
  924. if (symb != null && symb.getGradSymbLibNmbrList().size() >= atmpGrad) {
  925. TbVmsSymbLibDto atmpSymb = this.symbService.find(symb.getGradSymbLibNmbrList().get(atmpGrad));
  926. if (atmpSymb != null) {
  927. formObj.setImageData(atmpSymb.getImageData());
  928. formObj.setMemSymbLibNmbr(symb.getGradSymbLibNmbrList().get(atmpGrad));
  929. formObj.setBitmapId(atmpSymb.getDnldSymbLibNmbr());
  930. }
  931. else {
  932. formObj.setImageData(symb.getImageData());
  933. formObj.setMemSymbLibNmbr(formObj.getMemSymbLibNmbr());
  934. }
  935. }
  936. else {
  937. formObj.setImageData(formObj.getImageData());
  938. log.error("VmsManageService.makeVmsProvideForm: VMS({}), FormId({}), Atmp Symbol Not Found {} set form object image data.",
  939. ctlrNmbr, schedule.getVmsFormId(), formObj.getMemSymbLibNmbr());
  940. }
  941. }
  942. }
  943. else if (obj.getVmsFormObjectTypeCd() == 1 || obj.getVmsFormObjectTypeCd() == 2) {
  944. // 심볼, 이미지
  945. TbVmsSymbLibDto symb = this.symbService.find(formObj.getMemSymbLibNmbr());
  946. if (symb != null) {
  947. formObj.setImageData(symb.getImageData());
  948. }
  949. else {
  950. formObj.setImageData(obj.getImagData());
  951. log.error("VmsManageService.makeVmsProvideForm: VMS({}), FormId({}), Atmp Symbol Not Found {} set form symbol object image data.",
  952. ctlrNmbr, schedule.getVmsFormId(), formObj.getMemSymbLibNmbr());
  953. }
  954. }
  955. else {
  956. formObj.setImageData(obj.getImagData());
  957. }
  958. } // (formObj.getObjectKind() != eVmsFormObjectData.text_object_data.getValue())
  959. // 폼객체 유형별 Fill In
  960. switch(formObj.getObjectType()) {
  961. case 0: // 고정문자열
  962. case 201: // 동영상파일명
  963. case 301: // 스트리밍영상주소
  964. formObj.changeTextPosition(this.config.getFontSizeRatio());
  965. break;
  966. case 1: // 심볼
  967. case 2: // 파일이미지
  968. TbVmsSymbLibDto tSymb = this.symbService.find(formObj.getMemSymbLibNmbr());
  969. if (tSymb == null) {
  970. log.error("VmsManageService.makeVmsProvideForm: VMS({}), FormId({}), Not Found Symbol, File Image Symbol {}.",
  971. ctlrNmbr, schedule.getVmsFormId(), formObj.getMemSymbLibNmbr());
  972. }
  973. else {
  974. formObj.setImageData(tSymb.getImageData());
  975. }
  976. //formObj.setMemSymbLibNmbr(formObj.getMemSymbLibNmbr());
  977. break;
  978. case 17: // 1단,소통정보이미지1
  979. case 27: // 2단,소통정보이미지2
  980. case 37: // 3단,소통정보이미지3
  981. case 47: // 4단,소통정보이미지4
  982. case 167: // @우회소통정보이미지
  983. TbVmsSymbLibDto symb = this.symbService.find(formObj.getMemSymbLibNmbr());
  984. if (symb == null) {
  985. log.error("VmsManageService.makeVmsProvideForm: VMS({}), FormId({}), Not Found Traffic 1,2,3,4,detour Symbol {}.",
  986. ctlrNmbr, schedule.getVmsFormId(), formObj.getMemSymbLibNmbr());
  987. continue;
  988. }
  989. formObj.setMemSymbLibNmbr(formObj.getMemSymbLibNmbr());
  990. switch(formObj.getObjectType()) {
  991. case 167: // @우회소통정보이미지
  992. case 17: formObj.setIfscId(schedule.getFrstImgIfscId()); break; // 1단,소통정보이미지1
  993. case 27: formObj.setIfscId(schedule.getSecdImgIfscId()); break; // 2단,소통정보이미지2
  994. case 37: formObj.setIfscId(schedule.getThirImgIfscId()); break; // 3단,소통정보이미지3
  995. case 47: formObj.setIfscId(schedule.getFourImgIfscId()); break; // 4단,소통정보이미지4
  996. }
  997. TbVmsIfscTrafDto ifscTraf = this.ifscService.find(formObj.getIfscId());
  998. if (ifscTraf != null) {
  999. formObj.setIfscTrafGradCd(ifscTraf.getCmtrGradCd());
  1000. String trafImagId = symb.getSymbLibNmbr() + String.valueOf(ifscTraf.getCmtrGradCd());
  1001. TbVmsSymbLibDto trafSymb = this.symbService.find(trafImagId);
  1002. if (trafSymb != null) {
  1003. formObj.setMemSymbLibNmbr(trafImagId);
  1004. formObj.setImageData(trafSymb.getImageData());
  1005. formObj.setBitmapId(trafSymb.getDnldSymbLibNmbr());
  1006. }
  1007. else {
  1008. formObj.setImageData(symb.getImageData());
  1009. }
  1010. }
  1011. else {
  1012. log.error("VmsManageService.makeVmsProvideForm: VMS({}), FormId({}), Not Found IFSC Traffic 1,2,3,4,detour IFSC {}.",
  1013. ctlrNmbr, schedule.getVmsFormId(), formObj.getIfscId());
  1014. formObj.setIfscTrafGradCd(0);
  1015. formObj.setImageData(symb.getImageData());
  1016. }
  1017. break;
  1018. case 3: // 소통정보 배경이미지
  1019. TbVmsSymbLibDto bkSymb = this.symbService.find(formObj.getMemSymbLibNmbr());
  1020. if (bkSymb == null) {
  1021. log.error("VmsManageService.makeVmsProvideForm: VMS({}), FormId({}), Not Found Bk Traffic Symbol {}.",
  1022. ctlrNmbr, schedule.getVmsFormId(), formObj.getMemSymbLibNmbr());
  1023. continue;
  1024. }
  1025. formObj.setMemSymbLibNmbr(formObj.getMemSymbLibNmbr());
  1026. //formObj.setPosX(bkSymb.getPosX());
  1027. //formObj.setPosY(bkSymb.getPosY());
  1028. Image imgBmp = bkSymb.getImage(); // 원천이미지를 가지고 온다.
  1029. if (imgBmp == null) {
  1030. log.error("VmsManageService.makeVmsProvideForm: VMS({}), FormId({}), Image Data Error {}.",
  1031. ctlrNmbr, schedule.getVmsFormId(), formObj.getMemSymbLibNmbr());
  1032. continue;
  1033. }
  1034. BufferedImage formImage = new BufferedImage(imgBmp.getWidth(null), imgBmp.getHeight(null), BufferedImage.TYPE_INT_RGB);
  1035. Graphics2D g2d = formImage.createGraphics();
  1036. FloodFill floodFill = new FloodFill(imgBmp);
  1037. floodFill.setAntialiased(false);
  1038. bkSymb.getCellMap().forEach((cellId, cell) -> {
  1039. if (!cell.isValid()) {
  1040. return;
  1041. }
  1042. TbVmsIfscTrafDto cellTraf = this.ifscService.find(cell.getVmsIfscId());
  1043. if (cellTraf == null) {
  1044. return;
  1045. }
  1046. int cmtrGradCd = cellTraf.getCmtrGradCd();
  1047. int orgColor = floodFill.getImage().getRGB(cell.getPosX(), cell.getPosY());
  1048. int trfColor = VmsSymbService.getGradColor(cmtrGradCd);
  1049. if (orgColor != trfColor) {
  1050. floodFill.fill(cell.getPosX(), cell.getPosY(), VmsSymbService.getTrafColor(cmtrGradCd));
  1051. }
  1052. });
  1053. g2d.drawImage(floodFill.getImage(), 0, 0, imgBmp.getWidth(null), imgBmp.getHeight(null), null);
  1054. ByteArrayOutputStream out = new ByteArrayOutputStream();
  1055. try {
  1056. ImageIO.write(formImage, "bmp", out);
  1057. } catch (IOException e) {
  1058. log.error("VmsManageService.makeVmsProvideForm: Image Convert error: {}.", formObj.getMemSymbLibNmbr());
  1059. }
  1060. g2d.dispose();
  1061. formObj.setImageData(out.toByteArray());
  1062. break;
  1063. case 61: // 구간명
  1064. case 62: // 시점명
  1065. case 63: // 종점명
  1066. case 64: // 돌발유형
  1067. case 65: // 대응문구
  1068. case 66: // 통제유형 ==> 여기까지 돌발
  1069. case 71: // 발생장소
  1070. case 72: // INCD_TITL
  1071. case 73: // 통제시점명
  1072. case 74: // 통제종점명
  1073. case 75: // 00차로 차단
  1074. case 76: // 00월00일 ~ 00월00일
  1075. case 77: // 대응문구
  1076. case 78: // @통제유형 ==> 여기까지 공사/행사
  1077. case 81: // 돌발종류
  1078. case 82: // 해당도로
  1079. case 83: // 우회도로
  1080. case 84: // 발생장소 ==> 여기까지 돌발
  1081. // 돌발문안, 공사/행사문안 임
  1082. // TB_VMS_FORM_OBJECT_TYPE 테이블에 유형추가하고 돌발화면에서 필요한 항목 추가, TB_INCD_OCRR_VMS 테이블에 컬럼추가해야함
  1083. formObj.setTextData("");
  1084. TbVmsIncdDto event = schedule.getEvent();
  1085. if (event != null) {
  1086. switch(formObj.getObjectType()) {
  1087. case 82: //해당도로
  1088. case 83: //우회도로
  1089. case 61: formObj.setTextData(event.getVmsIfscNm()); break; //@구간명(사용안함)
  1090. case 62: //@시점명
  1091. case 73: formObj.setTextData(event.getStrtLctnNm()); break; //통제시점명
  1092. case 74: //통제종점명
  1093. case 63: formObj.setTextData(event.getEndLctnNm()); break; //@종점명
  1094. case 81: //돌발종류
  1095. case 64: formObj.setTextData(event.getVmsIncdDetlNm()); break; //@돌발유형
  1096. case 66: //@통제유형
  1097. case 78: formObj.setTextData(event.getVmsIncdRstrTypeNm()); break; //@통제유형
  1098. case 65: //@대응문구(사용안함-발생장소로 일단넣음)
  1099. case 77: //대응문구(사용안함-발생장소로 일단넣음)
  1100. case 84: //발생장소
  1101. case 71: formObj.setTextData(event.getOcrrLctnNm()); break; //발생장소
  1102. case 72: formObj.setTextData(event.getIncdTitl()); break; //@공사행사명
  1103. case 75: // 00차로 차단
  1104. int nLane = ItsUtils.parseIntDef(event.getIncdClsrLane(), 0);
  1105. if (nLane == 111111)
  1106. formObj.setTextData("차로 차단");
  1107. else
  1108. if (nLane > 0)
  1109. formObj.setTextData("일부 차단");
  1110. else
  1111. formObj.setTextData(" ");
  1112. break;
  1113. case 76: //00월00일 ~ 00월00일
  1114. try {
  1115. String strtDt = event.getIncdStrtDt();
  1116. String endDt = event.getIncdEndPrarDt();
  1117. String sFrom = strtDt.substring(4,6) + "월" + strtDt.substring(6,8) + "일 " + strtDt.substring(8,10) + "시";
  1118. String sTo = endDt.substring(4,6) + "월" + endDt.substring(6,8) + "일 " + endDt.substring(8,10) + "시";
  1119. formObj.setTextData(sFrom + " ~ " + sTo);
  1120. } catch(Exception e) {}
  1121. break;
  1122. }
  1123. }
  1124. if ("".equals(formObj.getTextData())) {
  1125. formObj.setTextData(" ");
  1126. }
  1127. formObj.changeTextPosition(this.config.getFontSizeRatio());
  1128. break;
  1129. case 401: // @관측장소
  1130. case 402: // @PM10
  1131. case 403: // @PM2.5
  1132. case 404: // @PM10등급
  1133. case 405: // @PM2.5등급
  1134. case 409: // @통합대기등급
  1135. case 410: // @통합대기
  1136. case 411: // @오존
  1137. case 412: // @오존등급
  1138. TbVmsAtmpDto atmp = this.atmpService.find(obj.getVmsIfscId());
  1139. if (atmp == null) {
  1140. log.error("VmsManageService.makeVmsProvideForm: VMS({}), FormId({}), Not Found Atmp {}.",
  1141. ctlrNmbr, schedule.getVmsFormId(), obj.getVmsIfscId());
  1142. }
  1143. else {
  1144. String unitGap = "";
  1145. boolean isUnit = false;
  1146. if (formObj.getTextData().contains(" -")) {
  1147. isUnit = true;
  1148. unitGap = " ";
  1149. } else if (formObj.getTextData().contains("-")) {
  1150. isUnit = true;
  1151. }
  1152. boolean isSetFontColor = true;
  1153. int fontGradeColorCd = 0;
  1154. if (formObj.getObjectType() == 401) {
  1155. isSetFontColor = false;
  1156. formObj.setTextData(atmp.getVmsDispNm());
  1157. } else if (formObj.getObjectType() == 402) {
  1158. formObj.setTextData(atmp.getPm10ValDesc(unitGap, isUnit));
  1159. fontGradeColorCd = atmp.getPm10Color();
  1160. } else if (formObj.getObjectType() == 403) {
  1161. formObj.setTextData(atmp.getPm25ValDesc(unitGap, isUnit));
  1162. fontGradeColorCd = atmp.getPm25Color();
  1163. } else if (formObj.getObjectType() == 404) {
  1164. formObj.setTextData(atmp.getPm10GradDesc());
  1165. fontGradeColorCd = atmp.getPm10Color();
  1166. } else if (formObj.getObjectType() == 405) {
  1167. formObj.setTextData(atmp.getPm25GradDesc());
  1168. fontGradeColorCd = atmp.getPm25Color();
  1169. } else if (formObj.getObjectType() == 409) {
  1170. formObj.setTextData(atmp.getAtmpGradDesc());
  1171. fontGradeColorCd = atmp.getAtmpColor();
  1172. } else if (formObj.getObjectType() == 410) {
  1173. formObj.setTextData(atmp.getAtmpValDesc());
  1174. fontGradeColorCd = atmp.getAtmpColor();
  1175. } else if (formObj.getObjectType() == 411) {
  1176. formObj.setTextData(atmp.getO3ValDesc(unitGap, isUnit));
  1177. fontGradeColorCd = atmp.getO3Color();
  1178. } else if (formObj.getObjectType() == 412) {
  1179. formObj.setTextData(atmp.getO3GradDesc());
  1180. fontGradeColorCd = atmp.getO3Color();
  1181. }
  1182. if (isSetFontColor && formObj.getFontColor() != 10) {
  1183. // 엘이디 고장난게 있어서 흰색으로 표출해야 해서 폰트색상이 흰색인 경우 그냥 흰색으로 표출하는 것으로.....
  1184. formObj.setFontColor(fontGradeColorCd);
  1185. }
  1186. }
  1187. if ("".equals(formObj.getTextData())) {
  1188. formObj.setTextData(" ");
  1189. }
  1190. formObj.changeTextPosition(this.config.getFontSizeRatio());
  1191. break;
  1192. case 101: // @주차장명
  1193. case 102: // @주차면수
  1194. case 103: // @주차가능면수
  1195. case 104: // @주차혼잡도
  1196. TbVmsParkDto park = this.parkService.find(obj.getVmsIfscId());
  1197. if (park == null) {
  1198. formObj.setTextData("-");
  1199. formObj.setFontColor(eVmsColor.color_red.getValue());
  1200. log.error("VmsManageService.makeVmsProvideForm: VMS({}), FormId({}), Not Found Parking {}.",
  1201. ctlrNmbr, schedule.getVmsFormId(), obj.getVmsIfscId());
  1202. }
  1203. else {
  1204. String textFmt = obj.getVmsDsplTxt().replaceAll("@", "");
  1205. switch(formObj.getObjectType()) {
  1206. case 101:// || //@주차장명
  1207. formObj.setTextData(park.getParkName());
  1208. break;
  1209. case 102:// || //@주차면수
  1210. formObj.setTextData(park.getTotalCo(textFmt));
  1211. break;
  1212. case 103:// || //@주차가능면수
  1213. formObj.setTextData(park.getRemainCo(textFmt));
  1214. formObj.setFontColor(park.getGradeColorCd());
  1215. break;
  1216. case 104:// //@주차혼잡도
  1217. formObj.setTextData(park.getParkingCngstSttsDesc());
  1218. formObj.setFontColor(park.getGradeColorCd());
  1219. break;
  1220. }
  1221. }
  1222. if ("".equals(formObj.getTextData())) {
  1223. formObj.setTextData(" ");
  1224. }
  1225. formObj.changeTextPosition(this.config.getFontSizeRatio());
  1226. break;
  1227. default:
  1228. //객체가 가변(소통정보 표출) 인 경우 가변문자를 설정하자....
  1229. Long vmsIfscId = 0L;
  1230. switch(formObj.getObjectType()) {
  1231. case 11: case 12: case 13: case 14: case 15: case 16: case 18: case 19:
  1232. vmsIfscId = schedule.getFrstVmsIfscId();
  1233. if (form.getVmsFormTypeCd() == eVmsFormType.eFormTp_figure.getValue() || form.getVmsFormTypeCd() == eVmsFormType.eFormTp_congest.getValue()) {
  1234. vmsIfscId = schedule.getVmsIfscId();
  1235. }
  1236. break;
  1237. case 161: case 162: case 163: case 164: case 165: case 166: case 168:
  1238. case 21: case 22: case 23: case 24: case 25: case 26: case 28:
  1239. vmsIfscId = schedule.getSecdVmsIfscId();
  1240. break;
  1241. case 31: case 32: case 33: case 34: case 35: case 36: case 38:
  1242. vmsIfscId = schedule.getThirVmsIfscId();
  1243. break;
  1244. case 41: case 42: case 43: case 44: case 45: case 46: case 48:
  1245. vmsIfscId = schedule.getFourVmsIfscId();
  1246. break;
  1247. case 91: case 92: //@축통행시간(고정), @축소통상황(고정)
  1248. case 93: case 94: case 95: case 96: // @축시점명(순환), @축종점명(순환), @축소통상황(순환), @축통행시간(순환)
  1249. vmsIfscId = schedule.getVmsIfscId();
  1250. break;
  1251. default: continue;
  1252. }
  1253. formObj.setTextData("");
  1254. ifscTraf = this.ifscService.find(vmsIfscId);
  1255. if (ifscTraf == null) {
  1256. log.error("VmsManageService.makeVmsProvideForm: VMS({}), FormId({}), Traffic IFSC Not Found {}.",
  1257. ctlrNmbr, schedule.getVmsFormId(), vmsIfscId);
  1258. continue;
  1259. }
  1260. switch(formObj.getObjectType()) {
  1261. case 11: case 21: case 31: case 41: case 161: //구간명
  1262. formObj.setTextData(ifscTraf.getRoadNm());
  1263. break;
  1264. case 12: case 22: case 32: case 42: case 93: case 162: //시점명
  1265. formObj.setTextData(ifscTraf.getDsplStrtNodeNm());
  1266. break;
  1267. case 13: case 23: case 33: case 43: case 94: case 163: //종점명
  1268. formObj.setTextData(ifscTraf.getDsplEndNodeNm());
  1269. break;
  1270. case 14: case 24: case 34: case 44: case 92: case 95: case 164: //소통상황
  1271. formObj.setTextData(trafGradeDesc(form.getVmsFormTypeCd(), ifscTraf.getCmtrGradCd()));
  1272. // 도형식 하단쪽에 엘이디 고장난게 있어서 흰색으로 표출해야 해서
  1273. // 폰트색상이 흰색인 경우 그냥 흰색으로 표출하는 것으로.....
  1274. if (formObj.getFontColor() != 10) {
  1275. formObj.setFontColor(gradeToColorCode(ifscTraf.getCmtrGradCd()));
  1276. }
  1277. break;
  1278. case 19: //소통상황(가변)
  1279. String gradText = trafGradeDesc(form.getVmsFormTypeCd(), ifscTraf.getCmtrGradCd());
  1280. if (ifscTraf.getCmtrGradCd() == eTrafficGrade.grade_smoothness.getValue()) {
  1281. gradText = String.format("소통원활 약 %d 분", ifscTraf.getTrvlHh());
  1282. }
  1283. formObj.setTextData(gradText);
  1284. formObj.setFontColor(gradeToColorCode(ifscTraf.getCmtrGradCd()));
  1285. break;
  1286. case 15: case 25: case 35: case 45: case 91: case 96: case 165: //통행시간
  1287. if (ifscTraf.getTrvlHh() > 0) {
  1288. String textFmt = obj.getVmsDsplTxt().replace("@", "");
  1289. if (textFmt.contains("0")) {
  1290. textFmt = textFmt.replace("0000", "%4d");
  1291. textFmt = textFmt.replace("000", "%3d");
  1292. textFmt = textFmt.replace("00", "%2d");
  1293. textFmt = textFmt.replace("0", "%d");
  1294. String textData = String.format(textFmt, ifscTraf.getTrvlHh());
  1295. formObj.setTextData(textData);
  1296. }
  1297. else {
  1298. formObj.setTextData(String.valueOf(ifscTraf.getTrvlHh()));
  1299. }
  1300. formObj.setFontColor(gradeToColorCode(ifscTraf.getCmtrGradCd()));
  1301. }
  1302. else
  1303. {
  1304. formObj.setTextData(" ");
  1305. formObj.setFontColor(eVmsColor.color_black.getValue());
  1306. }
  1307. break;
  1308. case 16: case 26: case 36: case 46: case 166: //통행속도
  1309. formObj.setTextData(String.valueOf(ifscTraf.getSped()));
  1310. formObj.setFontColor(gradeToColorCode(ifscTraf.getCmtrGradCd()));
  1311. break;
  1312. case 17: case 27: case 37: case 47: //방향이미지...???
  1313. break;
  1314. case 18: case 28: case 38: case 48: case 168: //지점명
  1315. formObj.setTextData(ifscTraf.getSpotNm());
  1316. break;
  1317. default: break;
  1318. }
  1319. formObj.changeTextPosition(this.config.getFontSizeRatio());
  1320. break;
  1321. }
  1322. } // (ii = 0; ii < vmsForm.getObjects().size()
  1323. // 동영상, 스트리밍 표출 텍스트 설정
  1324. List<VmsFormObject> tmpFormObjects = form.getObjects();
  1325. for (int kk = 0; kk < tmpFormObjects.size(); kk++) {
  1326. VmsFormObject tmpFormObj = tmpFormObjects.get(kk);
  1327. if (tmpFormObj.getObjectType() == 201) {
  1328. tmpFormObj.setTextData(videoFileName);
  1329. }
  1330. else if (tmpFormObj.getObjectType() == 301) {
  1331. tmpFormObj.setTextData(strmAddrNm);
  1332. }
  1333. }
  1334. } // (int ii = 0; ii < scheObj.size(); ii++)
  1335. });
  1336. log.info("VmsManageService.makeVmsProvideForm: {} ms.", elapsed.milliSeconds());
  1337. }
  1338. /**
  1339. * 데이터베이스에 저장할 폼 이미지를 생성한다.
  1340. */
  1341. public void makeVmsDatabaseForm() {
  1342. log.info("VmsManageService.makeVmsDatabaseForm: START.");
  1343. Elapsed elapsed = new Elapsed();
  1344. this.repoService.getCtlrMap().forEach((ctlrNmbr, vmsObj) -> {
  1345. if ("Y".equals(vmsObj.getDelYn())) {
  1346. return;
  1347. }
  1348. if (this.config.isFigureTrafficCenter()) {
  1349. //도형식폼의 하단소통정보위치를 가운데로 정렬하는 경우
  1350. makeVmsFigureFormPos(vmsObj);
  1351. }
  1352. if (this.config.isTextTrafficCenter() && "VMP2".equals(vmsObj.getTypeCd())) //2단 12열 일 경우 정렬
  1353. {
  1354. //1단교통정보의 이정을 가운데로 정렬하는 경우
  1355. makeVmsTextFormPos(vmsObj);
  1356. }
  1357. makeVmsDatabaseFormImage(vmsObj);
  1358. });
  1359. this.toggleFormSeq++;
  1360. if (this.toggleFormSeq >= 6) {
  1361. this.toggleFormSeq = 1;
  1362. }
  1363. log.info("VmsManageService.makeVmsDatabaseForm: {} ms.", elapsed.milliSeconds());
  1364. }
  1365. /**
  1366. * 데이터베이스에 저장할 폼 이미지를 생성한다.
  1367. * @param vmsObj
  1368. */
  1369. public void makeVmsDatabaseFormImage(TbVmsCtlrDto vmsObj) {
  1370. if (vmsObj == null) {
  1371. log.error("VmsManagerService.makeVmsDatabaseFormData: VMS Controller null data.");
  1372. return;
  1373. }
  1374. int formCnt = vmsObj.getFormManager().count();
  1375. if (formCnt == 0) {
  1376. log.error("VmsManagerService.makeVmsDatabaseFormData: VMS {}, Form Data Not Found.", vmsObj.getVmsCtlrNmbr());
  1377. return;
  1378. }
  1379. if (formCnt > vmsObj.getMaxPhaseNum()) {
  1380. log.error("VmsManagerService.makeVmsDatabaseFormData: VMS {}, Form Count Over: {}/{} EA.", vmsObj.getVmsCtlrNmbr(), formCnt, vmsObj.getMaxPhaseNum());
  1381. formCnt = vmsObj.getMaxPhaseNum();
  1382. }
  1383. for (int ii = 0; ii < formCnt; ii++) {
  1384. VmsForm pForm = vmsObj.getFormManager().getItem(ii);
  1385. pForm.drawForm(this.formService, this.fontService, this.config);
  1386. pForm.calVmsSchFormType();
  1387. pForm.makeVmsDsplMsgData(this.formService, this.symbService, this.ifscService);
  1388. // FTP 다운로드 하는 경우 폼을 FTP 디렉토리에 저장해야함
  1389. //if (pForm.getFileType() != VmsProtocolConst.P_FILE_TYPE_VIDEO && // 비디오
  1390. // pForm.getFileType() != VmsProtocolConst.P_FILE_TYPE_STREAM // 스트리밍영상 등은 로컬파일로 저장할 필요가 없음
  1391. //)
  1392. {
  1393. // 파일이름을 여기서 변경하면 ftp 파일명이 변경된다.
  1394. if (vmsObj.isFtpDownload()) {
  1395. String formFileName;
  1396. if (this.config.isImageSeqSave()) {
  1397. //시퀀스_운영모드-순서_폼유형-폼번호.bmp
  1398. formFileName = String.format("%d_%s%02d_%X%s.bmp", this.toggleFormSeq, vmsObj.getOperMode(), ii+1, pForm.getVmsSchFormType(), pForm.getVmsFormId());
  1399. }
  1400. else {
  1401. //운영모드-순서_폼유형-폼번호.bmp
  1402. formFileName = String.format("%s%02d_%X%s.bmp", vmsObj.getOperMode(), ii+1, pForm.getVmsSchFormType(), pForm.getVmsFormId());
  1403. }
  1404. pForm.setLocalFileName(vmsObj.getLocalFormDir() + formFileName);
  1405. pForm.setFtpFileName(vmsObj.getFtpFormDir() + formFileName);
  1406. pForm.saveToFile();
  1407. }
  1408. }
  1409. pForm.setSuccess(true);
  1410. if (this.debug.isDebug()) {
  1411. log.info("VmsManagerService.makeVmsDatabaseFormData: VMS {}, FORM {}, DnldFormNo {}, Objects {}. ScheduleType {}, FileType {}, File/FtpName {}/{}.",
  1412. vmsObj.getVmsCtlrNmbr(), pForm.getVmsFormId(), pForm.getDnldFormNo(), pForm.count(), eVmsScheduleType.getValue(pForm.getVmsSchFormType()), pForm.getFileType(), pForm.getLocalFileName(), pForm.getFtpFileName());
  1413. }
  1414. }
  1415. }
  1416. /**
  1417. * 도형식 VMS 하단 소통정보 좌표 위치 조정
  1418. * @param vmsObj
  1419. */
  1420. public void makeVmsFigureFormPos(TbVmsCtlrDto vmsObj) {
  1421. if (vmsObj == null) {
  1422. log.error("VmsManagerService.makeVmsFigureFormPos: VMS Controller null data.");
  1423. return;
  1424. }
  1425. int formCnt = vmsObj.getFormManager().count();
  1426. if (formCnt == 0) {
  1427. log.error("VmsManagerService.makeVmsFigureFormPos: VMS {}, Form Data Not Found.", vmsObj.getVmsCtlrNmbr());
  1428. return;
  1429. }
  1430. if (formCnt > vmsObj.getMaxPhaseNum()) {
  1431. log.error("VmsManagerService.makeVmsFigureFormPos: VMS {}, Form Count Over: {}/{} EA.", vmsObj.getVmsCtlrNmbr(), formCnt, vmsObj.getMaxPhaseNum());
  1432. formCnt = vmsObj.getMaxPhaseNum();
  1433. }
  1434. int arrowGap = 7;
  1435. int trafGap = 17;
  1436. int objCnt;
  1437. int formT;
  1438. VmsFormObject pArw;
  1439. VmsFormObject pStr;
  1440. VmsFormObject pEnd;
  1441. VmsFormObject pTrf;
  1442. int totW;
  1443. int left;
  1444. for (int ii = 0; ii < formCnt; ii++) {
  1445. VmsForm pForm = vmsObj.getFormManager().getItem(ii);
  1446. if (pForm.getVmsFormTypeCd() != eVmsFormType.eFormTp_figure.getValue()) {
  1447. //도형식배경소통정보 폼이 아닌경우 계산하지 않음
  1448. continue;
  1449. }
  1450. formT = pForm.getHeight() - 40; //하단소통정보 객체의 최대높이를 설정, 이것보다 작으면 위치조정 하지 않음
  1451. pArw = null;
  1452. pStr = null;
  1453. pEnd = null;
  1454. pTrf = null;
  1455. //소통상황 시점 -> 종점
  1456. //시점 -> 종점 소통상황
  1457. //위의 2가지 유형에 대하여 가운데 정렬
  1458. objCnt = pForm.count();
  1459. for (int jj = 0; jj < objCnt; jj++) {
  1460. VmsFormObject pFormObj = pForm.getItem(jj);
  1461. if (pFormObj.getPosY() < formT)
  1462. continue;
  1463. switch(pFormObj.getObjectType()) {
  1464. case 1: // 심볼 Y
  1465. case 2: // 이미지 Y
  1466. if ("T".equals(pFormObj.getTrfcFillCd()))
  1467. pArw = pFormObj;
  1468. break;
  1469. case 17: // @소통정보이미지 N
  1470. pArw = pFormObj;
  1471. break;
  1472. case 12: // @시점명 Y
  1473. case 93: // @축시점명(순환) Y
  1474. case 13: // @종점명 Y
  1475. case 94: // @축종점명(순환) Y
  1476. if (pFormObj.getObjectType() == 12 || pFormObj.getObjectType() == 93)
  1477. pStr = pFormObj;
  1478. else
  1479. pEnd = pFormObj;
  1480. break;
  1481. case 14: // @소통상황 Y
  1482. case 15: // @통행시간 Y
  1483. case 16: // @통행속도 N
  1484. case 95: // @축소통상황(순환) Y
  1485. case 96: // @축통행시간(순환) Y
  1486. pTrf = pFormObj;
  1487. break;
  1488. default: break;
  1489. }
  1490. }
  1491. if (pArw == null || pStr == null || pEnd == null || pTrf == null) {
  1492. continue;
  1493. }
  1494. int totalWidth = pStr.getTextWidth() + pArw.getTextWidth() + pEnd.getTextWidth() + pTrf.getTextWidth();
  1495. if (totalWidth > (pForm.getWidth() - arrowGap - arrowGap - trafGap - 10) ) {
  1496. arrowGap = 3;
  1497. trafGap = 10;
  1498. }
  1499. totW = pStr.getTextWidth() + arrowGap + pArw.getTextWidth() + arrowGap + pEnd.getTextWidth() + trafGap + pTrf.getTextWidth();
  1500. left = (pForm.getWidth() - totW) / 2;
  1501. if (pStr.getPosX() < pTrf.getPosX()) {
  1502. //시점 -> 종점 소통상황
  1503. pStr.setPosX(left);
  1504. pArw.setPosX(pStr.getPosX() + pStr.getTextWidth() + arrowGap);
  1505. pEnd.setPosX(pArw.getPosX() + pArw.getTextWidth() + arrowGap);
  1506. pTrf.setPosX(pEnd.getPosX() + pEnd.getTextWidth() + trafGap);
  1507. }
  1508. else {
  1509. //소통상황 시점 -> 종점
  1510. pTrf.setPosX(left);
  1511. pStr.setPosX(pTrf.getPosX() + pTrf.getTextWidth() + trafGap);
  1512. pArw.setPosX(pStr.getPosX() + pStr.getTextWidth() + arrowGap);
  1513. pEnd.setPosX(pArw.getPosX() + pArw.getTextWidth() + arrowGap);
  1514. }
  1515. }
  1516. }
  1517. /**
  1518. * 1단 텍스트 소통정보 좌표 위치 조정
  1519. * @param vmsObj
  1520. */
  1521. public void makeVmsTextFormPos(TbVmsCtlrDto vmsObj) {
  1522. // 시점 화살표 종점 의 좌표는 폼생성할때 정의된데로 하고
  1523. // 시점 화살표 종점의 전체 길이를 폼의 넓이로 환산하여 가운데 정렬
  1524. // 시점(오른쪽정렬) 화살표(의미없고) 종점(왼쪽정렬) 로 폼설정에서 설정하도록 한다.
  1525. // 시점/화살표/종점의 Y축 좌표도 설정한 데로 표출한다.
  1526. // 시점/화살표/종점을 폼의 가운데에 정렬하는 것이다.
  1527. if (vmsObj == null) {
  1528. log.error("VmsManagerService.makeVmsTextFormPos: VMS Controller null data.");
  1529. return;
  1530. }
  1531. int formCnt = vmsObj.getFormManager().count();
  1532. if (formCnt == 0) {
  1533. log.error("VmsManagerService.makeVmsTextFormPos: VMS {}, Form Data Not Found.", vmsObj.getVmsCtlrNmbr());
  1534. return;
  1535. }
  1536. if (formCnt > vmsObj.getMaxPhaseNum()) {
  1537. log.error("VmsManagerService.makeVmsTextFormPos: VMS {}, Form Count Over: {}/{} EA.", vmsObj.getVmsCtlrNmbr(), formCnt, vmsObj.getMaxPhaseNum());
  1538. formCnt = vmsObj.getMaxPhaseNum();
  1539. }
  1540. int objCnt;
  1541. int gapL;
  1542. VmsFormObject pArw;
  1543. VmsFormObject pStr;
  1544. VmsFormObject pEnd;
  1545. int totW;
  1546. int left;
  1547. for (int ii = 0; ii < formCnt; ii++) {
  1548. VmsForm pForm = vmsObj.getFormManager().getItem(ii);
  1549. if (pForm.getVmsFormTypeCd() != eVmsFormType.eFormTp_traf_1.getValue()) {
  1550. //소통상황(1단) 폼이 아닌경우 계산하지 않음
  1551. continue;
  1552. }
  1553. pArw = null;
  1554. pStr = null;
  1555. pEnd = null;
  1556. // 시점(12) -> 종점(13)
  1557. objCnt = pForm.count();
  1558. for (int jj = 0; jj < objCnt; jj++) {
  1559. VmsFormObject pFormObj = pForm.getItem(jj);
  1560. switch(pFormObj.getObjectType()) {
  1561. case 12: // @시점명 Y
  1562. pStr = pFormObj;
  1563. break;
  1564. case 13: // @종점명 Y
  1565. pEnd = pFormObj;
  1566. break;
  1567. default: break;
  1568. }
  1569. }
  1570. if (pStr == null || pEnd == null) {
  1571. continue;
  1572. }
  1573. for (int jj = 0; jj < objCnt; jj++) {
  1574. VmsFormObject pFormObj = pForm.getItem(jj);
  1575. switch(pFormObj.getObjectType()) {
  1576. case 1: // @심볼 Y
  1577. case 2: // @이미지 Y
  1578. case 17: // @소통정보이미지 Y
  1579. // if (pFormObj->TRFC_FILL_CD == "T")
  1580. if (pFormObj.getPosY() <= (pStr.getPosY()+pStr.getDsplHeight())) {
  1581. pArw = pFormObj;
  1582. }
  1583. break;
  1584. default: break;
  1585. }
  1586. }
  1587. if (pArw != null && pStr != null && pEnd!= null ) {
  1588. //시점 화살표 종점 순으로 되어 있어야 한다.
  1589. int nRange = pStr.getPosY() + pStr.getDsplHeight();
  1590. if (pArw.getPosY() <= nRange && pEnd.getPosY() <= nRange)
  1591. {
  1592. gapL = pArw.getPosX()- (pStr.getPosX()+ pStr.getTextWidth()); // 시점 화살표 사이의 간격
  1593. totW = (pEnd.getPosX()+ pEnd.getTextWidth()) - pStr.getPosX(); // 전체길이
  1594. left = (pForm.getWidth() - totW) / 2;
  1595. pStr.setPosX(left);
  1596. pArw.setPosX(pStr.getPosX()+ pStr.getTextWidth() + gapL);
  1597. pEnd.setPosX((left + totW) - pEnd.getTextWidth());
  1598. }
  1599. }
  1600. }
  1601. }
  1602. /**
  1603. * 폼유형에 따라 소통정보 등급에 해당하는 문자열 리턴
  1604. * @param formType
  1605. * @param cmtrGradCd
  1606. * @return
  1607. */
  1608. public String trafGradeDesc(int formType, int cmtrGradCd) {
  1609. if (formType == eVmsFormType.eFormTp_figure.getValue()) {
  1610. switch(cmtrGradCd) {
  1611. case 1: return this.config.getFigureTrafGrad1();
  1612. case 2: return this.config.getFigureTrafGrad2();
  1613. case 3: return this.config.getFigureTrafGrad3();
  1614. default: break;
  1615. }
  1616. }
  1617. else {
  1618. switch(cmtrGradCd) {
  1619. case 1: return this.config.getTextTrafGrad1();
  1620. case 2: return this.config.getTextTrafGrad2();
  1621. case 3: return this.config.getTextTrafGrad3();
  1622. default: break;
  1623. }
  1624. }
  1625. return " ";
  1626. }
  1627. /**
  1628. * 소통정보 등급에 따른 표출 색상코드를 리턴
  1629. * @param cmtrGradCd
  1630. * @return
  1631. */
  1632. public int gradeToColorCode(int cmtrGradCd) {
  1633. switch(cmtrGradCd) {
  1634. case 1: return eVmsColor.color_green.getValue();
  1635. case 2: return eVmsColor.color_amber.getValue();
  1636. case 3: return eVmsColor.color_red.getValue();
  1637. default: break;
  1638. }
  1639. return eVmsColor.color_green.getValue();
  1640. }
  1641. /**
  1642. * 제어기 상태정보 요청
  1643. */
  1644. public void requestStatus() {
  1645. this.repoService.getCtlrMap().forEach((ctlrNmbr, vmsObj) -> {
  1646. if ("Y".equals(vmsObj.getDelYn())) {
  1647. return;
  1648. }
  1649. vmsObj.addRequestData(new TcpServerSendData(eVmsOpCode.OP_VMS_STATUS_REQ, null));
  1650. });
  1651. }
  1652. }