[{"server":null,"owner":null,"id":"491586e9-42d2-4a32-9623-5aa09d4caa28","params":{"type":{"value":"EgsScheduled","datetime":1545377397,"status":null,"version":0},"settings":{"value":"{\"spawn_alarm_types\":[\"UndefinedSeaTarget\"],\"trace_highest_types\":[],\"trace_high_types\":[\"LargeShip\"],\"trace_normal_types\":[\"SeaTarget\"],\"trace_low_types\":[\"TinyShip\"],\"trace_lowest_types\":[\"Boat\"],\"trace_timeout\":500,\"trace_highest_timeout\":300,\"trace_high_timeout\":240,\"trace_normal_timeout\":180,\"trace_low_timeout\":60,\"trace_lowest_timeout\":20}","datetime":1545377415,"status":null,"version":0},"period_time":{"value":null,"datetime":1545228644,"status":null,"version":0},"error_text":{"value":null,"datetime":1545308686,"status":null,"version":0},"repeat":{"value":0,"datetime":1545228644,"status":null,"version":0},"period_unit":{"value":"Second","datetime":1545228644,"status":null,"version":0},"hash":{"value":"/tyYbOQUBmEnGq6FGSoldQ==","datetime":1545377894,"status":null,"version":0},"name":{"value":"Trace detector 2","datetime":1545228644,"status":null,"version":0},"enabled":{"value":true,"datetime":1545228644,"status":null,"version":0},"result":{"value":null,"datetime":1545228644,"status":null,"version":0},"period_count":{"value":1,"datetime":1545228644,"status":null,"version":0},"state":{"value":"ok.normal","datetime":1545308686,"status":null,"version":0},"script":{"value":"# имя: 'Trace detector 2'\r\n# описание: детектор слежения за целями в зоне\r\n# тип триггера: 'EgsScheduled'\r\n# создан: 2017.04.24 15.55.51, Сельченков Н.Ю.\r\n# изменен: '2018.12.21 11.38.12', Сельченков Н.Ю.\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.Collections.Generic.Dictionary(Guid, 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_timeout\" type=\"int\">500</param>\r\n        \r\n        <param name=\"trace_highest_timeout\" type=\"int\">300</param>\r\n        <param name=\"trace_high_timeout\" type=\"int\">240</param>\r\n        <param name=\"trace_normal_timeout\" type=\"int\">180</param>\r\n        <param name=\"trace_low_timeout\" type=\"int\">60</param>\r\n        <param name=\"trace_lowest_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_timeout         = settings.trace_timeout ?? 500\r\nconst trace_highest_timeout = settings.trace_highest_timeout ?? 300\r\nconst trace_high_timeout    = settings.trace_high_timeout ?? 240\r\nconst trace_normal_timeout  = settings.trace_normal_timeout ?? 180\r\nconst trace_low_timeout     = settings.trace_low_timeout ?? 120\r\nconst trace_lowest_timeout  = settings.trace_lowest_timeout ?? 60\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 get_zone(id as Guid) = from trigger.Module.Graphs select it[id] of type Zone single\r\n\r\nlet get_target(id as Guid) = if id in graph then graph[id] as MoveableObject\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 Guid) = \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\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)), target.Id) now\r\n    end now\r\nend\r\n\r\nlet fill_event(event as ZoneEvent, zone as Zone, target as MoveableObject) =\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 Ship then with target as Ship do iMO..\" \"..mMSI..\" \"..name \r\n                        else target.name\r\nend\r\n\r\nlet intersected_with(seq1, seq2) = from seq1 intersect seq2 count all > 0\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    if target.trace_priority isnt \"ignore\" then\r\n        \r\n        let target_type = target.GetType().Name\r\n\r\n        if target.trace_priority is \"DEFAULT\" then\r\n            target.trace_priority =\r\n                switch target_type\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\n                    \r\n        end\r\n        \r\n        let event   = ZoneEvent()\r\n        fill_event(event, zone, target)\r\n        event.alarm  = target_type in 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, graph.ServerId, trace_types, zone.area, trace_timeout)\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 trigger.Module.Graphs select many (from Values of type Zone) where trace_priority isnt \"ignore\" do process_zone(it) now\r\n\r\nfrom graph.Values of type MoveableObject where (trace_priority isnt \"ignore\") and (trace_priority isnt \"DEFAULT\") \r\ndo\r\n    let timeout =\r\n        switch trace_priority \r\n            when \"highest\" then trace_highest_timeout\r\n            when \"high\" then trace_high_timeout\r\n            when \"normal\" then trace_normal_timeout\r\n            when \"low\" then trace_low_timeout\r\n            when \"lowest\" then trace_lowest_timeout\r\n     \r\n    if seconds_passed(it[\"position\"].DateTime) > timeout then trace_priority = \"DEFAULT\"\r\nnow  \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          = ZoneEvent()\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        fill_event(event, zone, target)\r\n        if target.trace_priority isnt \"ignore\" then events.Add(event)\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\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\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\r\n","datetime":1545377892,"status":null,"version":0}},"entity":"item","operation":"create"}]