[{"server":null,"owner":null,"id":"e78d29d1-ae68-43b9-87e6-91684742da1e","params":{"type":{"value":"EgsScheduled","datetime":1559726340,"status":null,"version":0},"settings":{"value":"{\"spawn_alarm_types\":[\"UndefinedSeaTarget\"],\"trace_highest_types\":[],\"trace_high_types\":[\"LargeShip\"],\"trace_normal_types\":[\"Ship\",\"SmallShip\",\"UndefinedSeaTarget\",\"BuksirShip\"],\"trace_low_types\":[\"TinyShip\"],\"trace_lowest_types\":[],\"trace_polygon_timeout\":500,\"trace_target_timeout\":60,\"trace_undefined_timeout\":20}","datetime":1559726338,"status":null,"version":0},"period_time":{"value":null,"datetime":1559726338,"status":null,"version":0},"error_text":{"value":null,"datetime":1559726423,"status":null,"version":0},"repeat":{"value":0,"datetime":1559726338,"status":null,"version":0},"period_unit":{"value":"Second","datetime":1559726338,"status":null,"version":0},"hash":{"value":"W3PC/F536QI1ZkAIwKbQkg==","datetime":1559727035,"status":null,"version":0},"name":{"value":"Trace detector 3","datetime":1559726338,"status":null,"version":0},"enabled":{"value":true,"datetime":1559726338,"status":null,"version":0},"result":{"value":null,"datetime":1559726338,"status":null,"version":0},"period_count":{"value":1,"datetime":1559726338,"status":null,"version":0},"state":{"value":"ok.normal","datetime":1559726423,"status":null,"version":0},"script":{"value":"# имя: 'Trace detector 3'\r\n# описание: детектор слежения за целями в зоне\r\n# тип триггера: 'EgsScheduled'\r\n# создан: 2017.04.24 15.55.51, Сельченков Н.Ю.\r\n# изменен: 2019.03.06 11.00.00, Белоусов А.И.\r\n# изменен: '2019.06.05 13.30.35', Сельченков Н.Ю.\r\n# подробности: https://redmine.integra-s.com:11000/projects/eilyacuario/wiki/Trace_detector_2\r\n\r\nuse System.Math\r\n\r\nuse acuario2.types.BaseObject from acuario2.types\r\nuse acuario2.types.Zone from acuario2.types\r\nuse acuario2.types.PTZDevice from acuario2.types\r\nuse acuario2.types.MoveableObject from acuario2.types\r\nuse acuario2.types.UndefinedTarget from acuario2.types\r\nuse acuario2.types.Ship from acuario2.types\r\nuse acuario2.types.Aircraft from acuario2.types\r\nuse acuario2.types.ZoneAction from acuario2.types\r\nuse acuario2.client.ZoneEvent from acuario2.types\r\nuse acuario2.types.BaseEvent from acuario2.client \r\nuse acuario2.client.Protocol from acuario2.client\r\nuse acuario2.utils.DateTimeExtension\r\nuse utils.GeoPoint from GeoUtils\r\nuse utils.GeoUtils from GeoUtils\r\nuse acuario2.types.TraceDetectorSettings from acuario2.client \r\n\r\nuse System.Collections.Generic.List(GeoPoint) as GeoPointList\r\nuse System.Collections.Generic.List(ZoneEvent) as ZoneEventList\r\n\r\nuse new \r\n{ \r\n  ready      = false,\r\n  speed      = 0.0,\r\n  heading    = 0.0,\r\n  moving     = true,\r\n  too_fast   = false,\r\n  approached = false\r\n} as TargetContext\r\n\r\nuse System.Tuple(Guid, int) as TargetId\r\n\r\nuse System.Collections.Generic.Dictionary(TargetId, TargetContext) as ZoneContext\r\nuse System.Collections.Generic.Dictionary(Guid, ZoneContext) as Context\r\n\r\nuse typedef\r\n`\r\n    <root>\r\n        <param name=\"spawn_alarm_types\" type=\"list\"/>\r\n        \r\n        <param name=\"trace_highest_types\" type=\"list\"/>\r\n        <param name=\"trace_high_types\" type=\"list\"/>\r\n        <param name=\"trace_normal_types\" type=\"list\"/>\r\n        <param name=\"trace_low_types\" type=\"list\"/>\r\n        <param name=\"trace_lowest_types\" type=\"list\"/>\r\n        \r\n        <param name=\"trace_polygon_timeout\" type=\"int\">500</param>\r\n        <param name=\"trace_target_timeout\" type=\"int\">60</param>\r\n        <param name=\"trace_undefined_timeout\" type=\"int\">20</param>\r\n    </root>\r\n` as Settings\r\n\r\nconst settings = Settings(trigger.settings)\r\n\r\nconst spawn_alarm_types   = settings.spawn_alarm_types ?? string[](0)\r\nconst trace_highest_types = settings.trace_highest_types ?? string[](0)\r\nconst trace_high_types    = settings.trace_high_types ?? string[](0)\r\nconst trace_normal_types  = settings.trace_normal_types ?? string[](0)\r\nconst trace_low_types     = settings.trace_low_types ?? string[](0)\r\nconst trace_lowest_types  = settings.trace_lowest_types ?? string[](0)\r\n\r\nconst trace_polygon_timeout   = settings.trace_polygon_timeout ?? 500\r\nconst trace_target_timeout    = settings.trace_target_timeout ?? 60\r\nconst trace_undefined_timeout = settings.trace_undefined_timeout ?? 20\r\n\r\nconst trace_types = from trace_highest_types\r\n                    union trace_high_types\r\n                    union trace_normal_types\r\n                    union trace_low_types\r\n                    union trace_lowest_types\r\n                    to array\r\n\r\nlet rpcCatalog = trigger.Module.WampChannel.RealmProxy.RpcCatalog\r\n                  \r\nconst validType(typename as string) = Type.GetType(\"acuario2.types.\"..typename..\",acuario2.types\") isnt null\r\n\r\neval(from trace_types where it isnt validType do print \"type \"..it..\" not found\" now)\r\n\r\nassert(from trace_types all it is validType, \"invalid object type name\")                  \r\n\r\nonce context = null as Context\r\n\r\nlet events = ZoneEventList()\r\n\r\nlet unix_now() = DateTimeExtension.ToUnixTime(DateTime.UtcNow)\r\n\r\nlet seconds_passed(datetime as DateTime) = unix_now() - DateTimeExtension.ToUnixTime(datetime)\r\n\r\nlet make_target_id(target as MoveableObject) = new (target.Id, if target is UndefinedTarget then target.vendorID)\r\n\r\nlet get_zone(id as Guid) = from trigger.Module.Graphs select it[id] of type Zone single\r\n\r\nlet get_target(id as TargetId) = \r\n    let target = if id.Item1 in graph then graph[id.Item1] as MoveableObject\r\n    if (target isnt UndefinedTarget) or (target.vendorID is id.Item2) then target\r\nend\r\n\r\nlet get_zone_ctx(id as Guid) = \r\n    if not context.ContainsKey(id) then context[id] = ZoneContext()\r\n    context[id]\r\nend        \r\n\r\nlet get_target_ctx(zone_ctx as ZoneContext, id as TargetId) = \r\n    if zone_ctx isnt null then\r\n        if not zone_ctx.ContainsKey(id) then zone_ctx[id] = TargetContext() \r\n        zone_ctx[id]\r\n    end\r\nend        \r\n\r\nlet find_settings(zone as Zone, target as MoveableObject) = \r\n    let type     = target.GetType().Name\r\n    let guid     = string(target.Id) \r\n    let settings = zone.GetLinkedItems(TraceDetectorSettings) \r\n    \r\n    from settings where (guids isnt null) and (guid in guids) concat\r\n    ( from settings where (types isnt null) and (type in types) ) concat\r\n    ( from settings where (types is empty ) and (guids is empty) )\r\n    try first\r\nend\r\n                                   \r\nif context is null then\r\n    print \"initializing zones context...\"\r\n    context = Context()\r\n    from graph.Values of type MoveableObject where trace_zones isnt empty do\r\n        let target = it\r\n        from trace_zones do get_target_ctx(get_zone_ctx(Guid(it)), make_target_id(target)) now\r\n    end now\r\nend\r\n\r\nlet create_event(zone as Zone, target as MoveableObject) =\r\n    if (zone.trace_priority isnt \"ignore\") and (target.trace_priority isnt \"ignore\") and (find_settings(zone, target) isnt null) then\r\n        let event         = ZoneEvent()\r\n        event.owner       = string(zone.Id)\r\n        event.server      = string(target.ServerId)\r\n        event.position    = target.position\r\n        event.detector    = string(trigger.Id)\r\n        event.target      = string(target.Id)\r\n        event.target_type = target.GetType().Name\r\n        event.target_info = switch target \r\n                            when UndefinedTarget x then x.vendor..\" \"..x.vendorID\r\n                            when Ship x            then x.iMO..\" \"..x.mMSI..\" \"..x.name \r\n                            else                        target.name\r\n        event\r\n    end\r\nend\r\n\r\nlet intersected_with(seq1, seq2) = from seq1 intersect seq2 count all > 0\r\n\r\nlet is_one_of(target as MoveableObject, types as string[]) = (target.GetType().Name in types) or (target.Types is intersected_with types)\r\n\r\nlet select_priority(target as MoveableObject) =\r\n    target.trace_priority = \r\n        switch target.GetType().Name\r\n            when in trace_highest_types then \"highest\"\r\n            when in trace_high_types then \"high\"\r\n            when in trace_normal_types then \"normal\"\r\n            when in trace_low_types then \"low\"\r\n            when in trace_lowest_types then \"lowest\"\r\n            else switch target.Types \r\n                when intersected_with trace_highest_types then \"highest\"\r\n                when intersected_with trace_high_types then \"high\"\r\n                when intersected_with trace_normal_types then \"normal\"\r\n                when intersected_with trace_low_types then \"low\"\r\n                when intersected_with trace_lowest_types then \"lowest\"\r\n                else \"DEFAULT\"\r\nend\r\n\r\nlet process_target(zone as Zone, target as MoveableObject, enter as bool) = \r\n    print(if enter then \"ENTER\" else \"EXIT\", zone, target)\r\n    \r\n    if target.trace_zones is null then target.trace_zones = string[](0)\r\n    if enter then target.trace_zones = from target.trace_zones union string(zone.Id) to array \r\n    else target.trace_zones = from target.trace_zones except string(zone.Id) to array\r\n    \r\n    let event = create_event(zone, target)\r\n    if event isnt null then\r\n        event.alarm  = is_one_of(target, spawn_alarm_types)\r\n        event.action = if enter then \"enter\" else \"exit\"\r\n        events.Add(event)\r\n    end\r\nend \r\n\r\nlet process_zone(zone as Zone) = \r\n    let result = await Protocol.GetObjectsByPoligon(rpcCatalog, zone.ServerId ?? Guid.Empty, trace_types, zone.area, trace_polygon_timeout)\r\n    let result = from result where it in graph select graph[it] of type MoveableObject select make_target_id(it) to array\r\n    \r\n    let zone_ctx = get_zone_ctx(zone.Id)\r\n    \r\n    let exited  = from zone_ctx.Keys except result to array\r\n    let entered = from result except zone_ctx.Keys to array\r\n    \r\n    from exited \r\n        do zone_ctx.Remove(it) \r\n        select get_target(it) of type MoveableObject \r\n        do process_target(zone, it, false) now\r\n    \r\n    from entered \r\n        do get_target_ctx(zone_ctx, it)\r\n        select get_target(it) of type MoveableObject \r\n        do process_target(zone, it, true) now\r\nend\r\n\r\nfrom graph.Values of type MoveableObject where (trace_priority isnt \"ignore\")\r\ndo\r\n    let timeout         = if it is UndefinedTarget then trace_undefined_timeout else trace_target_timeout\r\n    let is_default      = trace_priority is \"DEFAULT\" \r\n    let must_be_default = seconds_passed(it[\"position\"].DateTime) > timeout \r\n\r\n    if must_be_default then trace_priority = \"DEFAULT\"\r\n    else if is_default then select_priority(it)\r\nnow\r\n\r\nfrom trigger.Module.Graphs select many (from Values of type Zone) where area isnt empty do process_zone(it) now\r\n\r\nlet check_target(zone as Zone, polygon as GeoPointList, zone_ctx as ZoneContext, target as MoveableObject, target_ctx as TargetContext, settings as TraceDetectorSettings) = \r\n    let add_event(alarm as bool?, action as ZoneAction, value_before as double, value_after as double, participants as Guid[]) = \r\n        let event = create_event(zone, target)\r\n        if event isnt null then\r\n            event.alarm        = alarm ?? false\r\n            event.action       = action\r\n            event.value_before = string(value_before)\r\n            event.value_after  = string(value_after)\r\n            event.participants = if participants is empty then null else string[](participants)\r\n            events.Add(event)\r\n        end\r\n    end\r\n    \r\n    let get_geo_point(obj as MoveableObject) = \r\n        let p    = GeoPoint((obj as BaseObject).position)\r\n        p.Height = GeoUtils.GetZoneApproxHeight(polygon, p)\r\n        p\r\n    end\r\n    \r\n    let point = get_geo_point(target) \r\n    \r\n    if target_ctx.ready then\r\n        let moving = target.speed > settings.stop_threshold\r\n        if moving isnt target_ctx.moving then \r\n            add_event(settings.stop_alarm, if moving then \"start\" else \"stop\", target_ctx.speed, target.speed, null)\r\n            target_ctx.moving = moving\r\n        else if moving then\r\n            let too_fast = target.speed > settings.speed_limit\r\n            if too_fast isnt target_ctx.too_fast then \r\n                add_event(settings.speed_limit_alarm, if too_fast then \"too_fast\" else \"not_too_fast\", target_ctx.speed, target.speed, null)\r\n                target_ctx.too_fast = too_fast\r\n            end\r\n        \r\n            let delta = Math.Abs(target.speed - target_ctx.speed)\r\n            if delta > settings.speed_change_threshold then \r\n                add_event(settings.speed_change_alarm, \"severe_speed_change\", target_ctx.speed, target.speed, null)\r\n            end\r\n            \r\n            let delta = Math.Abs(target.heading - target_ctx.heading)\r\n            if delta > settings.heading_change_threshold then \r\n                add_event(settings.heading_change_alarm, \"severe_heading_change\", target_ctx.heading, target.heading, null)\r\n            end\r\n        end\r\n          \r\n        let participants =  \r\n            from zone_ctx select get_target(Key) of type MoveableObject \r\n            where (it isnt target) and (point.Distance(get_geo_point(it)) < settings.approach_threshold)\r\n            order by Id select Id to array\r\n            \r\n        let approached = participants isnt empty\r\n        if approached isnt target_ctx.approached then\r\n            add_event(settings.approach_alarm, if approached then \"dangerous_approach\" else \"no_dangerous_approach\", 0, 0, participants)\r\n            target_ctx.approached = approached\r\n        end\r\n    end\r\n    \r\n    target_ctx.speed   = target.speed\r\n    target_ctx.heading = target.heading\r\n    target_ctx.ready   = true\r\nend\r\n\r\nfrom context do\r\n    let zone     = get_zone(Key)\r\n    let polygon  = GeoUtils.ParsePolygon(zone.area, zone.area_heights)\r\n    let zone_ctx = Value\r\n    from zone_ctx do\r\n        let target = get_target(Key) \r\n        if target isnt null then \r\n            let settings = find_settings(zone, target) \r\n            if settings isnt null then check_target(zone, polygon, zone_ctx, target, Value, settings)\r\n        end\r\n    now\r\nnow\r\n\r\nif events isnt empty then \r\n    let request = from events select many ExportCreate(Guid(server)) to array\r\n    Protocol.Put(rpcCatalog, request)\r\nend\r\n","datetime":1559727035,"status":null,"version":0}},"entity":"item","operation":"create"}]