[{"server":null,"owner":null,"id":"ccd70933-4ce0-42ca-80fb-7cfa18f324a4","params":{"type":{"value":"EgsScheduled","datetime":1573050242,"status":null,"version":0},"settings":{"value":"{\"url\":\"http://localhost:1986/axis2/services/Iv7Server\",\"snapshot_width\":320,\"snapshot_height\":240,\"trace_highest_factor\":\"10000\",\"trace_high_factor\":\"2\",\"trace_normal_factor\":1,\"trace_low_factor\":0.5,\"trace_lowest_factor\":0.2,\"trace_disable_timeout\":\"180\",\"multi_trace_enabled\":true,\"max_adjust_iterations\":10}","datetime":1556014486,"status":null,"version":0},"period_time":{"value":null,"datetime":1553503978,"status":null,"version":0},"error_text":{"value":null,"datetime":1573031650,"status":null,"version":0},"repeat":{"value":0,"datetime":1553503978,"status":null,"version":0},"period_unit":{"value":"Second","datetime":1553503978,"status":null,"version":0},"hash":{"value":"MbPOfK5rLPq9OQhP0hu6TQ==","datetime":1573050280,"status":null,"version":0},"name":{"value":"PTZ Tracer 4","datetime":1572968858,"status":null,"version":0},"enabled":{"value":true,"datetime":1556103711,"status":null,"version":0},"result":{"value":null,"datetime":1553503978,"status":null,"version":0},"period_count":{"value":1,"datetime":1553503978,"status":null,"version":0},"state":{"value":"ok.normal","datetime":1573031650,"status":null,"version":0},"script":{"value":"# имя: 'PTZ Tracer 4'\r\n# описание: детектор слежения за целями в зоне\r\n# тип триггера: 'EgsScheduled'\r\n# создан: 2017.04.24 15.55.51, Сельченков Н.Ю.\r\n# изменен: 2019.03.04 17.25.59, Белоусов А.И.\r\n# изменен: '2019.11.06 18.24.40', Сельченков Н.Ю.\r\n# подробности: https://redmine.integra-s.com:11000/projects/eilyacuario/wiki/PTZ_Tracer_4\r\n\r\nuse System.Uri\r\nuse System.Convert\r\nuse System.Math\r\nuse System.Threading.Tasks.Task\r\nuse System.Text.RegularExpressions.Regex\r\nuse Newtonsoft.Json.JsonConvert from Newtonsoft.Json\r\nuse System.Collections.Generic.Dictionary(string, object) as Dictionary\r\nuse System.Collections.ArrayList\r\nuse Newtonsoft.Json.Linq.JArray\r\nuse Newtonsoft.Json.Linq.JObject\r\nuse System.Environment\r\n\r\nuse acuario2.types.BaseObject from acuario2.types\r\nuse acuario2.types.SpatialObject from acuario2.types\r\nuse acuario2.types.MoveableObject from acuario2.types\r\nuse acuario2.types.VideoCamera from acuario2.types\r\nuse acuario2.types.Zone from acuario2.types\r\nuse acuario2.types.PTZDevice from acuario2.types\r\nuse acuario2.types.IntegraVideo7 from acuario2.types\r\n\r\nuse acuario2.utils.DateTimeExtension\r\n\r\nuse utils.GeoPoint from GeoUtils\r\nuse utils.GeoUtils from GeoUtils\r\nuse utils.Matrix3D from GeoUtils\r\n\r\nuse integravideo.client.Iv7Server from IntegraVideo7Client\r\nuse integravideo.client.MemoryMappedFrame from IntegraVideo7Client\r\nuse new { code = 0, user_code = 0, result = null as ArrayList } as CallMethod2Result\r\nuse new { pan = 0.0, tilt = 0.0, zoom = 0.0 } as PTZ\r\nuse new { ptzdev = nil as PTZDevice, task = nil as Task } as MyTask\r\nuse System.Collections.Generic.List(MyTask) as MyTaskList\r\nuse new { item = nil as MoveableObject, priority = 0.0, zones = nil as Zone[], zone = nil as Zone } as Target\r\n\r\nuse typedef\r\n`\r\n    <root>\r\n        <param name=\"url\">http://localhost:1986/axis2/services/Iv7Server</param>\r\n        <param name=\"snapshot_width\" type=\"int\">320</param>\r\n        <param name=\"snapshot_height\" type=\"int\">240</param>\r\n        <param name=\"trace_highest_factor\" type=\"real\">10.0</param>\r\n        <param name=\"trace_high_factor\" type=\"real\">2.0</param>\r\n        <param name=\"trace_normal_factor\" type=\"real\">1.0</param>\r\n        <param name=\"trace_low_factor\" type=\"real\">0.5</param>\r\n        <param name=\"trace_lowest_factor\" type=\"real\">0.2</param>\r\n        <param name=\"trace_disable_timeout\" type=\"int\">60</param>\r\n        <param name=\"multi_trace_enabled\" type=\"bool\">false</param>\r\n        <param name=\"max_adjust_iterations\" type=\"int\">10</param>\r\n    </root>\r\n` as Settings\r\n\r\nconst settings = Settings(trigger.settings)\r\nconst uri      = Uri(settings.url)\r\n\r\nonce tasks = MyTaskList()\r\n\r\n######################################################\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 allowed_to_trace(ptzdev as PTZDevice, target as MoveableObject) = (ptzdev.trace_types is empty) or is_one_of(target, ptzdev.trace_types)\r\n\r\nlet max_priority(item as MoveableObject) = if int(item.internal_priority) > int(item.trace_priority) then item.internal_priority else item.trace_priority\r\n\r\nlet ignored(item as MoveableObject) = (item.trace_priority is \"ignore\") or (item.internal_priority is \"DEFAULT\")\r\n\r\n######################################################\r\n\r\nlet iv7 = Iv7Server() \r\niv7.Url = string(uri)\r\n\r\nlet sys_params = \"\" \r\n\r\nlet сall_method2(name as string, args as object, log as bool) = \r\n    let request  = JsonConvert.SerializeObject(args)\r\n    let response = iv7.CallMethod2(name, request, sys_params)\r\n    let res      = JsonConvert.DeserializeObject(response, CallMethod2Result) as CallMethod2Result\r\n    let ok       = (res.code is 0) and (res.user_code is 0)\r\n    if (not ok) and log then\r\n        print request\r\n        print sys_params\r\n        print response\r\n    end\r\n    if ok then res.result\r\nend\r\n\r\nlet logon { login = \"\", password = \"\" } = \r\n    sys_params = JsonConvert.SerializeObject(new { session_id = \"egs\", timeout = 5, relay = string[](0), login = login, password = password })\r\n    сall_method2(\"video-client:Logon\", it, on) is not null\r\nend\r\n\r\nlet get_ptz { key2 = \"\", QueryAll = true, login = \"\", password = \"\" } = \r\n    let res = сall_method2(\"ptzclient:Command\", it, on)\r\n    if res isnt null then \r\n        let ptz  = PTZ()\r\n        let obj  = res[0] as JObject\r\n        ptz.pan  = (obj[\"pan\"] as double) / 100\r\n        ptz.tilt = (obj[\"tilt\"] as double) / 100\r\n        ptz.zoom = (obj[\"zoom\"] as double) / 10000\r\n        ptz\r\n    end\r\nend\r\n\r\nlet _set_ptz { key2 = \"\", PanTo = -1, TiltTo = -1, ZoomTo = -1, login = \"\", password = \"\" } = сall_method2(\"ptzclient:Command\", it, on) is not null\r\nlet set_ptz(login as string, password as string, key2 as string, ptz as PTZ) = _set_ptz { key2 = key2, PanTo = ptz.pan * 100 as int, TiltTo = ptz.tilt * 100 as int, ZoomTo = ptz.zoom * 10000 as int, login = login, password = password } \r\n\r\nlet open_mapping { udp_id = \"\", key2 = \"\", unique = \"\" } = сall_method2(\"video-client:OpenMapping\", it, off) is not null\r\nlet close_mapping { unique = \"\" } = сall_method2(\"video-client:CloseMapping\", it, off) is not null\r\n\r\nlet get_param_from_urls(obj as VideoCamera, pattern as string) = \r\n    let regex = Regex(pattern)\r\n    from obj.url select regex.Match(it) where Success select Groups[1].Value first\r\nend\r\n\r\nlet get_key2(obj as VideoCamera) = get_param_from_urls(obj, \"key2=(.+)[&|;]?\")\r\nlet get_udp_id(obj as VideoCamera) = get_param_from_urls(obj, \"udp_id=([0-9]{1,})&\")\r\nlet get_login(obj as VideoCamera) = get_param_from_urls(obj, \"iv7://(.+):.+@\")\r\nlet get_password(obj as VideoCamera) = get_param_from_urls(obj, \"iv7://.+:(.+)@\")\r\n\r\n######################################################\r\n\r\nlet get_priority_factor(priority as Priority) = \r\n    switch priority \r\n        when \"highest\" then settings.trace_highest_factor ?? 10\r\n        when \"high\" then settings.trace_high_factor ?? 2\r\n        when \"normal\" then settings.trace_normal_factor ?? 1\r\n        when \"low\" then settings.trace_low_factor ?? 0.5\r\n        when \"lowest\" then settings.trace_lowest_factor ?? 0.2\r\n        else 0\r\nend    \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 shorten_angle(angle as double) = \r\n    if      angle < -180 then angle + 360\r\n    else if angle > 180  then angle - 360\r\n    else                      angle\r\nend\r\n\r\n######################################################\r\n\r\nlet recalibrate(point1 as GeoPoint, point2 as GeoPoint, matrix as Matrix3D, ptzdev as PTZDevice) =  \r\n    let ptz                   = PTZ()\r\n    let arr                   = GeoUtils.recalibrate(point1, point2, matrix)\r\n    ptz.tilt                  = Math.Round(arr[0], 2, \"AwayFromZero\")\r\n    ptz.pan                   = Math.Round(arr[1], 2, \"AwayFromZero\")\r\n    let range                 = arr[2]\r\n    let min_zoom_distance     = if ptzdev.min_zoom_distance > 0 then ptzdev.min_zoom_distance else 0\r\n    let min_zoom_limit_factor = if ptzdev.min_zoom_limit_factor > 0 then ptzdev.min_zoom_limit_factor else 0\r\n    let max_zoom_distance     = if ptzdev.max_zoom_distance > 0 then ptzdev.max_zoom_distance else 1500\r\n    let max_zoom_limit_factor = if ptzdev.max_zoom_limit_factor > 0 then ptzdev.max_zoom_limit_factor else 1\r\n    #let in_zoom_limit_factor  = if ptzdev.in_zoom_limit_factor > 0 then ptzdev.in_zoom_limit_factor else 1\r\n    ptz.zoom =  \r\n                                if range < min_zoom_distance then min_zoom_limit_factor \r\n                                else if range > max_zoom_distance then max_zoom_limit_factor \r\n                                else ((range - min_zoom_distance)/(max_zoom_distance - min_zoom_distance))*(max_zoom_limit_factor - min_zoom_limit_factor) + min_zoom_limit_factor\r\n    ptz.zoom                  = Math.Round(ptz.zoom, 2, \"AwayFromZero\")\r\n    ptz\r\nend\r\n\r\nlet get_assumed_target_pos(point as GeoPoint, heading as double, distance as double) =\r\n    let WGS_84_RADIUS_EQUATOR = 6378137.0\r\n    let result                = point.Destination(heading, distance, WGS_84_RADIUS_EQUATOR)\r\n    result.Lattitude          = GeoUtils.toDeg(result.Lattitude) \r\n    result.Longitude          = GeoUtils.toDeg(result.Longitude) \r\n    result\r\nend\r\n\r\nlet trace_target(ptzdev as PTZDevice, zone as Zone, target as MoveableObject) =\r\n\r\n    let camera_pos = with ptzdev as SpatialObject do \r\n        let p    = GeoPoint(geo_position)\r\n        p.Height = geo_height\r\n        p\r\n    end\r\n    \r\n    let polygon    = GeoUtils.ParsePolygon(zone.area, zone.area_heights)\r\n    let target_pos = with target as BaseObject do\r\n        let p    = GeoPoint(position)\r\n        p.Height = GeoUtils.GetZoneApproxHeight(polygon, p)\r\n        p\r\n    end\r\n    \r\n    let v = ptzdev.calibrationMatrix\r\n    if (v isnt null) and camera_pos.Valid and target_pos.Valid then\r\n    \r\n        let key2   = get_key2(ptzdev as VideoCamera)\r\n        let udp_id = get_udp_id(ptzdev as VideoCamera)\r\n        let unique = ptzdev.Id..\".mmap\"\r\n        \r\n        let videoServer = from ptzdev.GetLinkedItems(IntegraVideo7) try single\r\n        let login       = (videoServer?.login) ??? get_login(ptzdev as VideoCamera) \r\n        let password    = (videoServer?.password) ??? get_password(ptzdev as VideoCamera) \r\n        \r\n        let matrix = Matrix3D\r\n        (\r\n            v[0], v[1], v[2], 0, \r\n            v[3], v[4], v[5], 0, \r\n            v[6], v[7], v[8], 0, \r\n               0,    0,    0, 1\r\n        )\r\n\r\n        logon { login = login, password = password }\r\n        \r\n        let max_iterations = settings.max_adjust_iterations ?? 10\r\n        let focus_time     = if ptzdev.focus_time > 0 then ptzdev.focus_time else 5\r\n        let zoom_time      = if ptzdev.zoom_time > 0 then ptzdev.zoom_speed else 5\r\n        let zoom_speed     = 1 / zoom_time  \r\n        let pan_speed      = if ptzdev.pan_speed > 0  then ptzdev.pan_speed  else 36\r\n        let tilt_speed     = if ptzdev.tilt_speed > 0 then ptzdev.tilt_speed else 36\r\n        let parallel_ptz   = ptzdev.parallel_ptz\r\n        let heading        = GeoUtils.toRad(target.heading) \r\n        let speed          = target.speed\r\n        let old            = get_ptz { key2 = key2, login = login, password = password }\r\n        let old            = get_ptz { key2 = key2, login = login, password = password }\r\n        let prev_pos       = target_pos\r\n        let iter ()        = \r\n            let ptz       = recalibrate(camera_pos, prev_pos, matrix, ptzdev)\r\n            let pan_time  = Math.Abs(shorten_angle(ptz.pan  - old.pan)) / pan_speed \r\n            let tilt_time = Math.Abs(shorten_angle(ptz.tilt - old.tilt)) / tilt_speed\r\n            let zoom_time = Math.Abs(ptz.zoom - old.zoom) / zoom_speed\r\n            let times     = new [ focus_time, pan_time, tilt_time, zoom_time ]\r\n            let time      = if parallel_ptz then (from times max) else (from times sum)\r\n            let pos       = get_assumed_target_pos(target_pos, heading, speed * time)\r\n            let err       = prev_pos.Distance(pos)\r\n            prev_pos      = pos\r\n            #print(ptz, pos, err)\r\n            new { ptz = ptz, pos = pos, time = time, err = err } \r\n        end\r\n\r\n        let result = from 1 to max_iterations select iter () order by err try first\r\n\r\n        print(\"TRACE\", ptzdev, target, zone, target_pos, target.heading, target.speed, result.pos, login, password, result.ptz)\r\n        \r\n        set_ptz(login, password, key2, result.ptz)\r\n        \r\n        open_mapping { udp_id = udp_id, key2 = key2, unique = unique }\r\n        \r\n        await Task.Delay(int(Math.Round(result.time * 1000)))\r\n        \r\n        let frame = try MemoryMappedFrame(unique)\r\n\r\n        #print(frame.Index, frame.Width, frame.Height, frame.Size)\r\n        if (frame isnt null) and frame.Valid then \r\n            let jpg               = frame.ToJPEG(settings.snapshot_width ?? 320, settings.snapshot_height ?? 240)\r\n            target.trace_snapshot = Convert.ToBase64String(jpg)\r\n        else\r\n            target[\"trace_snapshot\"].Set(null, \"invalid\", null)\r\n        end\r\n    end\r\nend\r\n\r\nlet completed = from tasks where task.IsCompleted to array \r\nfrom completed do tasks.Remove(it) now\r\n\r\nlet busy(ptzdev as PTZDevice) = from tasks any it.ptzdev is ptzdev\r\n\r\nlet ptzdevs = from trigger.Module.Graphs\r\n              select many (from Values of type PTZDevice) \r\n              where (calibrationMatrix isnt empty) \r\n                and (it[\"trace_enabled\"].Value isnt null)\r\n                and (trace_enabled or seconds_passed(it[\"trace_enabled\"].DateTime) > (settings.trace_disable_timeout ?? 60))\r\n                and (it isnt busy)\r\n              do trace_enabled = true\r\n              to list\r\n              \r\nlet zones = from ptzdevs select many GetLinkedItems(Zone) distinct bind string(Id) to it\r\n\r\nlet makeTarget(item as MoveableObject) =\r\n    let target   = Target()\r\n    target.item  = item\r\n    target.zones = from item.trace_zones where it in zones select zones[it] \r\n                      order by get_priority_factor(trace_priority) desc to array\r\n    target.zone     = from target.zones try first \r\n    target.priority = seconds_passed(item[\"trace_snapshot\"].DateTime) \r\n                    * get_priority_factor(max_priority(item))\r\n                    * get_priority_factor(target.zone?.trace_priority)\r\n    target                \r\nend\r\n\r\nlet runTasks(target as Target) =\r\n    let continue = true\r\n    from target.zones while continue do\r\n        let zone = it\r\n        from GetLinkedItems(PTZDevice) where (it in ptzdevs) and (it is allowed_to_trace target.item) while continue do\r\n            ptzdevs.Remove(it)\r\n            let task    = MyTask()\r\n            task.ptzdev = it \r\n            task.task   = async trace_target(it, zone, target.item)\r\n            tasks.Add(task)\r\n            continue = settings.multi_trace_enabled ?? false\r\n        end now\r\n    end now\r\nend\r\n\r\nfrom graph.Values of type MoveableObject \r\n    where (trace_zones isnt empty) and (it isnt ignored) \r\n    select makeTarget(it) where zone isnt nil order by priority desc\r\n    while ptzdevs.Count > 0 and priority > 0\r\n    do runTasks(it) now\r\n    \r\n","datetime":1573050280,"status":null,"version":0}},"entity":"item","operation":"create"}]