Пример #1
0
 def detect(self):
     m = Motion()
     m.computeFrameFeatures(self.path)
     seconds = m.getFakeTime()
     if (seconds.__len__() > 0):
         self.fake(seconds)
     else:
         self.original()
Пример #2
0
 def calc_base_frame(self):
     gray_frames = []
     for i in range(0, len(self.Video)):
         gray_image = cv2.cvtColor(self.Video[i], cv2.COLOR_BGR2GRAY)
         gray_image = np.array(gray_image).astype(int)
         gray_frames.append(gray_image)
     m = Motion()
     Baseframe = m.calcBaseFrame(gray_frames)
     Baseframe = np.uint8(Baseframe)
     cv2.imshow('Base Frame', Baseframe)
     cv2.waitKey(1000)
Пример #3
0
 def __init__(self):
     self.__origTime = 0
     self.__tcc = TrackCoordConv()
     self.__speedAndAngle = Motion()
     self.__origSpeed = 0.0
     self.__origAcc = 0.0
     self.__minDt = 0
     self.__maxDt = 0
     self.__minX = 0.0
     self.__maxX = 0.0
     self.__npivots = 0
Пример #4
0
 def Motion_Residue(self):
     gray_frames = []
     for i in range(0, len(self.Video)):
         gray_image = cv2.cvtColor(self.Video[i], cv2.COLOR_BGR2GRAY)
         gray_image = np.array(gray_image).astype(int)
         gray_frames.append(gray_image)
     m = Motion()
     Baseframe = m.calcBaseFrame(gray_frames)
     Baseframe = np.uint8(Baseframe)
     for i in range(0, len(gray_frames)):
         frameResidue = gray_frames[i] - Baseframe
         frameResidue = np.uint8(frameResidue)
         cv2.imshow('Motion Residue', frameResidue)
         cv2.waitKey(30)
     cv2.destroyAllWindows()
Пример #5
0
def main():

    # Init motion detection and socketserver
    socketClient = SocketClient()
    motion = Motion(socketClient)
    #capture = Capture()

    # Start program
    motion.start()
    socketClient.start()
    #capture.start()
    
    # Wait until threads die
    motion.join()
    socketClient.join()
Пример #6
0
    def step(self, action, show_plot=False):

        #action[1]=self.accl_to_gas(action[1],self._state.v)
        #action[0]=action[0]-np.deg2rad(90)
        #action[0]*=-1

        self.gas = action[1]
        self.steer = action[0]
        self.brake = action[2]

        #nst,rw,ter,info=self.ENV.step(action) # take a random action
        #self.frame[0:96,0:96,:]=np.array(nst)

        #pos=self.ENV.car.hull.position
        #vel=np.sqrt(self.ENV.car.hull.linearVelocity[0]**2+self.ENV.car.hull.linearVelocity[1]**2)
        #ang=self.ENV.car.hull.angle
        #ang*=-1
        #ang=ang+np.deg2rad(90)#-ang

        nst, _ = Motion.get_next_state(self._state, action[1], action[0])
        nst = nst.array()
        pos = [nst[0], nst[1]]
        ang = nst[3]
        vel = nst[2]
        self._state = State(x=pos[0], y=pos[1], yaw=ang, v=vel)
        #self.Dstr.get_origin_shift(self._state)
        #self.Dstr.shift_trajectory()
        rw = 0
        ter = 0
        info = 0
        _traj, _dind, _end = self._Map_Tracker.run(self._state)
        return [0, 0, 0, vel], [_traj, _dind, _end], [pos[0], pos[1],
                                                      ang], nst, rw, ter, info
Пример #7
0
    def __init__(self):
        Thread.__init__(self)
        self.view = View()
        self.view.start()

        self.motion = Motion(HBridges().TB6612FNG)
        '''    
        self.motion.startDriving(1000, 1)
        time.sleep(1)
        self.motion.startDriving(1000, 0)
        time.sleep(2)
        self.motion.startRotating(1000, 1)
        time.sleep(2)
        self.motion.stopRotating()
        self.motion.startRotating(1000, 0)
        time.sleep(2)
        self.motion.stopRotating()'''

        self.streamThread = StreamThread(self.view)
        #self.motionThread = MotionThread(self.view)

        self.streamThread.start()
Пример #8
0
 def speedAndAngleOf(self, time0_) :
     '''
     @summary: Returns movement vector of point as a function of time.
     @param time0_: Time to compute movement of feature for, in
                    either seconds or milliseconds.
     @return: Movement vector of feature at time0_, as a Motion object.
     '''
     time0 = self._toSec(time0_)
     if self.__npivots==0 :
        return Motion(0,0)
     if time0==0 or time0==self.__origTime :
        return self.__speedAndAngle
     #dt = otime - self.__origTime
     dt = time0- self.__origTime
     if dt>self.__maxDt or dt<self.__minDt :
        return Motion(0,0)
     bearing = self.__tcc.bearingOf(self.xOfDt(dt))
     if bearing > 180.0 :
        bearing = bearing - 180.0
     else :
        bearing = bearing + 180.0
     return Motion((self.__origSpeed+self.__origAcc*dt)*1944.0, bearing)
Пример #9
0
    def createStormTrack(self, points, stormTrackStart, hazardStart, hazardEnd, motion, footprint, returnTime1=False):
        # Create point track

        # Input:
        #    points -- list of [(lon,lat), time)] where time is in milliseconds past 1970
        #       What about climate data?
        #    motion -- (speed, bearing)
        #    footprint -- what is that?
        #    
        i = 0
        
        latLonList=[]
        timeList=[]
        for latLon, t in points:
            lat, lon = latLon

            latLon = LatLonCoord(lat, lon)
            #exec "latLon"+`i`+ "= latLon"
            latLonList.append(latLon)
            # Convert from ms to seconds
            #exec "time"+`i`+"=t"
            timeList.append(t)
            i +=1
            
        drtTime = hazardStart
        # Initialize
        pt = PointTrack()
        if motion == 0:
            speed = 20 # kts
            bearing = 225 # degrees
        else:
            speed, bearing = motion
        motion = Motion(speed, bearing)
         
        if len(points) == 1:
            pt._PT_latLon_motion_origTime(latLonList[0], timeList[0], motion, drtTime)
        elif len(points) == 2:
            pt._PT_two_latLon_origTime(latLonList[0], timeList[0], latLonList[1], timeList[1], drtTime)
        elif len(points) == 3:
            pt._PT_three_latLon_origTime(latLonList[0], timeList[0], latLonList[1], timeList[1], latLonList[2], timeList[2], drtTime)
        if returnTime1: return pt, timeList[0]
        else: return pt
Пример #10
0
def main():

    # Init motion detection and socketserver
    socketClient = SocketClient()
    motion = Motion(socketClient)
    #capture = Capture()

    # Start program
    motion.start()
    socketClient.start()
    #capture.start()

    # Wait until threads die
    motion.join()
    socketClient.join()
Пример #11
0
    def move_agents(self, action_list):
        """Updates the environment with the actions in the list.

        Conversion from the action into the actual change of coordinate (check
        if this action is possible is in self.move_agent)

        Returns the current state that is used by the neural net as well as the rewards
        collected by the moves of the action_list

        Parameters
        ----------
        action_list : list
            Containing the actions for each agent (0: up, 1: right, 2: down, 3: left, 4: stay)
            Agents are ordered as in the self.agents list.
            Dimension: 1 x Number of agents
        Return
        -------
        ndarray: 
            History over the visible trash, for each saved timestep. (Dimension: grid_height x grid_width x saved_timesteps)
        
        ndarray:

        """
        agent_idx = 0
        reward_list = []
        for action in action_list:
            d_pos = Motion(action).value
            reward_list.append(self.move_agent(agent_idx, d_pos))
            agent_idx = agent_idx + 1

        self.generate_new_trash()
        # Save the current conditions (Stempeluhr) as next Timestep
        self.save_condition_new_timestep()
        history_visible_trash, history_agents, current_pos_agent = self.export_known_data(
        )

        # numpy array n_agents x grid_height x grid_widht X (n_number_timesteps x Channel (own_position (one_hot_vector), other_position (one_hot_vector), garbish)
        return history_visible_trash, history_agents, current_pos_agent, reward_list
Пример #12
0
    parser.add_argument('--port',
                        type=int,
                        default=9559,
                        help='Naoqi port number')

    args = parser.parse_args()
    session = qi.Session()
    session.connect('tcp://' + args.ip + ':' + str(args.port))

    faceDetection = FaceDetection(session, args)
    #faceDetection.StopTracking()
    #model1 = Model1()
    #model2 = Model2()
    showImage = ShowImage(session, args)
    navigate = Navigate(session, args)
    motion = Motion(session, args)
    motion.external_avoidance()
    right = 0
    left = 1

    count = 0
    while count < 1:
        #the argument predicted by the pose
        #command=model1.predict()
        motion.init()
        #command=getcommand(ToF = False)
        command = 4
        faceDetection.StartTracking()
        while not faceDetection.got_face:
            time.sleep(1.0)
        showImage.show(command)
Пример #13
0
#print('hello')
scene = bge.logic.getCurrentScene()
top = scene.objects['b_top']
bot = scene.objects['b_bot']
left = scene.objects['b_left']
right = scene.objects['b_right']
cam = scene.objects['Camera']
#print('objects ok')

# WELL-ALIGNED (GAP 0) POSITIONS ARE:
# top z=2   (4x2x1)+ROTX90
# bot z=-2  (4x2x1)+ROTX90
# left x=-2 (2x4x1)+ROTX90
# right x=2 (2x4x1)+ROTX90

m_top = Motion()
m_bot = Motion()
m_left = Motion()
m_right = Motion()
motor_names = [b'top', b'bot', b'left', b'right']
motors = {b'top': m_top, b'bot': m_bot, b'left': m_left, b'right': m_right}

for m in motors.values():
    m.setMinVelocity(0)
    m.setMaxVelocity(10)
    m.setAccelerationTime(2)
    m.setDecelerationTime(2)
    m.setCurrentPosition(0)

# MOVE TO START POSITION
m_top.startMotion(0, 20)
Пример #14
0
 def __init__(self, parent, primary, user, password, manifest=None, udp_data=None, address=None):
     self.parent      = parent
     self.user        = user
     self.password    = password
     self.connected   = 0
     self.parent.logger.info("FoscamMJPEG:init: Adding manifest=%s upd_data=%s" % (manifest,udp_data))
     self.auth_mode   = 0
     # Use manifest values if passed in.
     if manifest is not None:
         self.name  = manifest['name']
         if address is None:
             self.parent.send_error("FoscamMJPEG:init:%s: address must be passed in when using manifest for: " % (name,manifest))
             return False
         self.address = address
         # TODO: It's ok to not have drivers?  Just let query fill out the info? 
         if not 'drivers' in manifest:
             self.parent.send_error("FoscamMJPEG:init:%s: no drivers in manifest: " % (name,manifest))
             return False
         drivers = manifest['drivers']
         # Get the things we need from the drivers, the rest will be queried.
         self.ip    = long2ip(drivers['GV2'])
         self.port  = drivers['GV3']
         # New in 0.3
         if 'GV10' in drivers:
             self.auth_mode = drivers['GV10']
         else:
             # Old default was digest
             self.auth_mode = 1
         if 'GV11' in drivers:
             self.sys_ver = drivers['GV11']
         else:
             # Old default was digest
             self.sys_ver = 0.0
         self.full_sys_ver = self.sys_ver
     elif udp_data is not None:
         self.name      = udp_data['name']
         self.address   = udp_data['id'].lower()
         self.auth_mode = self._get_auth_mode(udp_data['sys'])
         self.ip        = udp_data['ip']
         self.port      = udp_data['port']
         self.sys_ver   = self._parse_sys_ver(udp_data['sys'])
         self.full_sys_ver = str(udp_data['sys'])
     else:
         self.parent.send_error("FoscamMJPEG:init:%s: One of manifest or udp_data must be passed in." % (address))
         return False
     # Add the Camera
     self.parent.logger.info("FoscamMJPEG:init: Adding %s %s auth_mode=%d" % (self.name,self.address,self.auth_mode))
     super(FoscamMJPEG, self).__init__(parent, self.address, self.name, primary, manifest)
     self.set_driver('GV1',  VERSION_MAJOR, uom=56, report=False)
     self.set_driver('GV12', VERSION_MINOR, uom=56, report=False)
     self.set_driver('GV2',  ip2long(self.ip), uom=56, report=False)
     self.set_driver('GV3',  self.port, uom=56, report=False)
     self.set_driver('GV10', self.auth_mode, uom=25, report=False)
     self.set_driver('GV11', self.sys_ver, uom=56, report=False)
     # Init these in case we can't query.
     self.status = {}
     self.params = {}
     for param in ('led_mode', 'alarm_motion_armed', 'alarm_mail', 'alarm_motion_sensitivity', 'alarm_motion_compensation', 'alarm_upload_interval'):
         if not param in self.params:
             self.params[param] = 0
     # Call query to pull in the params before adding the motion node.
     self.query();
     # Add my motion node now that the camera is defined.
     self.motion = Motion(parent, self, manifest)
     # Tell the camera to ping the parent server on motion.
     self._set_alarm_params({
         'motion_armed': 1,
         'http':         1,
         'http_url':     "http://%s:%s/motion/%s" % (parent.server.server_address[0], parent.server.server_address[1], self.motion.address)
     });
     # Query again now that we have set paramaters
     self.query();
     self.parent.logger.info("FoscamMJPEG:init: Added camera at %s:%s '%s' %s" % (self.ip,self.port,self.name,self.address))
Пример #15
0
 def __init__(self, view):
     Thread.__init__(self)
     self.motion = Motion(HBridges().TB6612FNG)
     self.view = view
Пример #16
0
class Controller(Thread):
    view = None
    streamer = None
    maxSpeed = 1000
    maxRotSpeed = 500

    streamThread = None

    def __init__(self):
        Thread.__init__(self)
        self.view = View()
        self.view.start()

        self.motion = Motion(HBridges().TB6612FNG)
        '''    
        self.motion.startDriving(1000, 1)
        time.sleep(1)
        self.motion.startDriving(1000, 0)
        time.sleep(2)
        self.motion.startRotating(1000, 1)
        time.sleep(2)
        self.motion.stopRotating()
        self.motion.startRotating(1000, 0)
        time.sleep(2)
        self.motion.stopRotating()'''

        self.streamThread = StreamThread(self.view)
        #self.motionThread = MotionThread(self.view)

        self.streamThread.start()
        #self.motionThread.start()

    def run(self):
        try:
            while True:
                if self.view.interrupts["main"] == 1:
                    if self.view.interrupts["connect_camera"] == 1:
                        self.streamThread.targetIp = self.view.targetUdpIp
                        self.streamThread.targetPort = self.view.targetUdpPort
                        self.streamThread.startUdp()
                        self.view.interrupts["connect_camera"] = 0
                        self.view.interrupts["main"] = 0
                    if self.view.interrupts["abort_connection"] == 1:
                        self.streamThread.stopUdp()
                        self.view.interrupts["abort_connection"] = 0
                        self.view.interrupts["main"] = 0
                    if self.view.closed == 1:
                        print("Closing")
                        self.streamThread.stop()
                        self.view.interrupts["main"] = 0
                        break
                    if self.view.interrupts["set_speed"] == 1:
                        speed = self.view.getForSpeed()
                        rotSpeed = self.view.getRotSpeed(
                        ) * self.maxRotSpeed / self.maxSpeed
                        if speed < 0:
                            rotSpeed = -rotSpeed
                        speeds = [speed - rotSpeed, speed + rotSpeed]
                        for motorNr, sp in enumerate(speeds):
                            dir = 0
                            if sp > 0:
                                dir = 1
                            self.motion.setMotorDirection(motorNr, dir)
                            motorSpeed = min(self.maxSpeed,
                                             self.maxSpeed * abs(sp) / 100)
                            print(motorSpeed)
                            self.motion.setSpeed(motorNr, motorSpeed)
                        self.view.interrupts["set_speed"] = 0
                        self.view.interrupts["main"] = 0

        finally:
            self.motion.resetPinModes()
            pass
Пример #17
0
class FoscamMJPEG(Node):
    """ 
    Node that contains the Hub connection settings 
    """

    def __init__(self, parent, primary, user, password, manifest=None, udp_data=None, address=None):
        self.parent      = parent
        self.user        = user
        self.password    = password
        self.connected   = 0
        self.parent.logger.info("FoscamMJPEG:init: Adding manifest=%s upd_data=%s" % (manifest,udp_data))
        self.auth_mode   = 0
        # Use manifest values if passed in.
        if manifest is not None:
            self.name  = manifest['name']
            if address is None:
                self.parent.send_error("FoscamMJPEG:init:%s: address must be passed in when using manifest for: " % (name,manifest))
                return False
            self.address = address
            # TODO: It's ok to not have drivers?  Just let query fill out the info? 
            if not 'drivers' in manifest:
                self.parent.send_error("FoscamMJPEG:init:%s: no drivers in manifest: " % (name,manifest))
                return False
            drivers = manifest['drivers']
            # Get the things we need from the drivers, the rest will be queried.
            self.ip    = long2ip(drivers['GV2'])
            self.port  = drivers['GV3']
            # New in 0.3
            if 'GV10' in drivers:
                self.auth_mode = drivers['GV10']
            else:
                # Old default was digest
                self.auth_mode = 1
            if 'GV11' in drivers:
                self.sys_ver = drivers['GV11']
            else:
                # Old default was digest
                self.sys_ver = 0.0
            self.full_sys_ver = self.sys_ver
        elif udp_data is not None:
            self.name      = udp_data['name']
            self.address   = udp_data['id'].lower()
            self.auth_mode = self._get_auth_mode(udp_data['sys'])
            self.ip        = udp_data['ip']
            self.port      = udp_data['port']
            self.sys_ver   = self._parse_sys_ver(udp_data['sys'])
            self.full_sys_ver = str(udp_data['sys'])
        else:
            self.parent.send_error("FoscamMJPEG:init:%s: One of manifest or udp_data must be passed in." % (address))
            return False
        # Add the Camera
        self.parent.logger.info("FoscamMJPEG:init: Adding %s %s auth_mode=%d" % (self.name,self.address,self.auth_mode))
        super(FoscamMJPEG, self).__init__(parent, self.address, self.name, primary, manifest)
        self.set_driver('GV1',  VERSION_MAJOR, uom=56, report=False)
        self.set_driver('GV12', VERSION_MINOR, uom=56, report=False)
        self.set_driver('GV2',  ip2long(self.ip), uom=56, report=False)
        self.set_driver('GV3',  self.port, uom=56, report=False)
        self.set_driver('GV10', self.auth_mode, uom=25, report=False)
        self.set_driver('GV11', self.sys_ver, uom=56, report=False)
        # Init these in case we can't query.
        self.status = {}
        self.params = {}
        for param in ('led_mode', 'alarm_motion_armed', 'alarm_mail', 'alarm_motion_sensitivity', 'alarm_motion_compensation', 'alarm_upload_interval'):
            if not param in self.params:
                self.params[param] = 0
        # Call query to pull in the params before adding the motion node.
        self.query();
        # Add my motion node now that the camera is defined.
        self.motion = Motion(parent, self, manifest)
        # Tell the camera to ping the parent server on motion.
        self._set_alarm_params({
            'motion_armed': 1,
            'http':         1,
            'http_url':     "http://%s:%s/motion/%s" % (parent.server.server_address[0], parent.server.server_address[1], self.motion.address)
        });
        # Query again now that we have set paramaters
        self.query();
        self.parent.logger.info("FoscamMJPEG:init: Added camera at %s:%s '%s' %s" % (self.ip,self.port,self.name,self.address))

    def update_config(self, user, password, udp_data=None):
        self.parent.logger.info("FoscamMJPEG:update_config: upd_data=%s" % (udp_data))
        self.user        = user
        self.password    = password
        if udp_data is not None:
            self.name      = udp_data['name']
            self.auth_mode = self._get_auth_mode(udp_data['sys'])
            self.ip        = udp_data['ip']
            self.port      = udp_data['port']
            self.sys_ver   = self._parse_sys_ver(udp_data['sys'])
            self.full_sys_ver = str(udp_data['sys'])
        self.set_driver('GV2',  ip2long(self.ip), uom=56, report=False)
        self.set_driver('GV3',  self.port, uom=56, report=False)
        self.set_driver('GV10', self.auth_mode, uom=25, report=False)
        self.set_driver('GV11', self.sys_ver, uom=56, report=False)
        self.query()
        
    def query(self, **kwargs):
        """ query the camera """
        # pylint: disable=unused-argument
        self.parent.logger.info("FoscamMJPEG:query:start:%s" % (self.name))
        # Get current camera params.
        self._get_params();
        # Get current camera status.
        self._get_status();
        # Set GV4 Responding
        self.set_driver('GV4', self.connected, uom=2, report=False)
        if self.params:
            self.set_driver('GV5', self.params['led_mode'], uom=25, report=False) # ,uom=int, report=False ?
            self.set_driver('GV6', self.params['alarm_motion_armed'], uom=2, report=False) # ,uom=int, report=False ?
            self.set_driver('GV7', self.params['alarm_mail'], uom=2, report=False)
            self.set_driver('GV8', self.params['alarm_motion_sensitivity'], uom=25, report=False)
            self.set_driver('GV9', self.params['alarm_motion_compensation'], uom=2, report=False)
            self.set_driver('GV13', self.params['alarm_upload_interval'], uom=2, report=False)
        self.report_driver()
        self.parent.logger.info("FoscamMJPEG:query:done:%s" % (self.name))
        return True

    def _http_get(self, path, payload = {}):
        """ Call http_get on this camera for the specified path and payload """
        return self.parent.http_get(self.ip,self.port,self.user,self.password,path,payload,auth_mode=self.auth_mode)
        
    def _http_get_and_parse(self, path, payload = {}):
        """ 
        Call http_get and parse the returned Foscam data into a hash.  The data 
        all looks like:  var id='000C5DDC9D6C';
        """
        data = self._http_get(path,payload)
        if data is False:
            return False
        ret  = {}
        for item in data.splitlines():
            param = item.replace('var ','').replace("'",'').strip(';').split('=')
            ret[param[0]] = param[1]
        return ret
    
    def _get_params(self):
        """ Call get_params and get_misc on the camera and store in params """
        params = self._http_get_and_parse("get_params.cgi")
        if not params:
            self.parent.send_error("FoscamMJPEG:_get_params:%s: Unable to get_params" % (self.name))
            self.connected = 0
            return False
        self.connected = 1
        self.params = self._http_get_and_parse("get_params.cgi")
        misc = self._http_get_and_parse("get_misc.cgi")
        self.params['led_mode'] = misc['led_mode']

    def poll(self):
        """ Nothing to poll?  """
        #response = os.system("ping -c 1 -w2 " + self.ip + " > /dev/null 2>&1")
        return

    def long_poll(self):
        self.parent.logger.info("FoscamMJPEG:long_poll:%s:" % (self.name))
        # get_status handles properly setting self.connected and the driver
        # so just call it.
        self._get_status()
    
    def _parse_sys_ver(self,sys_ver):
        """ 
        Given the camera system version as a string, parse into what we 
        show, which is the last 2 digits
        """
        vnums = sys_ver.split(".")
        if len(vnums) == 4:
            self.parent.logger.debug("FoscamMJPEG:parse_sys_ver: %s 0=%s 1=%s 2=%s 3=%s",sys_ver,vnums[0],vnums[1],vnums[2],vnums[3])
            ver = myfloat("%d.%d" % (int(vnums[2]),int(vnums[3])),2)
            self.parent.logger.debug("FoscamMJPEG:parse_sys_ver: ver=%f",ver)
            return ver
        else:
            return None
        
    def _get_auth_mode(self,sys_ver):
        """ 
        Given the camera system version as a string, figure out the 
        authorization mode.  Default is 0 (Basic) but if last 2 
        digits of sys_ver are > 2.52 then use 1 (Digest)
        """
        auth_mode = 0
        vnums = sys_ver.split(".")
        if int(vnums[2]) >= 2 and int(vnums[3]) > 52:
            auth_mode = 1
        return auth_mode
        
    def _set_alarm_params(self,params):
        """ 
        Set the sepecified alarm params on the camera
        """
        self.parent.logger.info("FoscamMJPEG:set_alarm_params:%s: %s" % (self.name,params))
        return self._http_get("set_alarm.cgi",params)

    def _set_misc_params(self,params):
        """ 
        Set the sepecified misc params on the camera
        """
        self.parent.logger.info("FoscamMJPEG:set_misc_params:%s: %s" % (self.name,params))
        return self._http_get("set_misc.cgi",params)

    def _decoder_control(self,params):
        """ 
        Pass in decoder command
        """
        self.parent.logger.info("FoscamMJPEG:set_decoder_control:%s: %s" % (self.name,params))
        return self._http_get("decoder_control.cgi",params)

    def get_motion_status(self):
        """
        Called by motion node to return the current motion status.
        0 = Off
        1 = On
        2 = Unknown
        """
        self._get_status()
        if not self.status or not 'alarm_status' in self.status:
            return 2
        return int(self.status['alarm_status'])

    def set_motion_status(self,value):
        """
        Called by motion node to set the current motion status.
        """
        self.status['alarm_status'] = value

    def _get_status(self,report=True):
        """ 
        Call get_status on the camera and store in status
        """
        # Can't spit out the device name cause we might not know it yet.
        self.parent.logger.info("FoscamMJPEG:get_status: %s:%s" % (self.ip,self.port))
        # Get the status
        status = self._http_get_and_parse("get_status.cgi")
        if status:
            connected = 1
            self.status = status
            # Update sys_ver if it's different
            if self.full_sys_ver != str(self.status['sys_ver']):
                self.parent.logger.debug(self.status)
                self.parent.logger.info("FoscamMJPEG:get_status:%s: New sys_ver %s != %s" % (self.name,self.full_sys_ver,str(self.status['sys_ver'])))
                self.full_sys_ver = str(self.status['sys_ver'])
                new_ver = self._parse_sys_ver(self.status['sys_ver'])
                if new_ver is not None:
                    self.sys_ver = new_ver
                    self.set_driver('GV11', self.sys_ver, uom=56, report=True)
        else:
            self.parent.send_error("FoscamMJPEG:_get_params:%s: Failed to get_status" % (self.name))
            # inform the motion node there is an issue if we have a motion node
            if hasattr(self,'motion'):
                self.motion.motion(2)
            else:
                self.status['alarm_status'] = 2
            connected = 0
        if connected != self.connected:
            self.connected = connected
            self.set_driver('GV4', self.connected, uom=2, report=True)

    def _set_alarm_param(self, driver=None, param=None, **kwargs):
        value = kwargs.get("value")
        if value is None:
            self.parent.send_error("_set_alarm_param not passed a value: %s" % (value) )
            return False
        # TODO: Should use the _driver specified function instead of int.
        if not self._set_alarm_params({ param: int(value)}):
            self.parent.send_error("_set_alarm_param failed to set %s=%s" % (param,value) )
        # TODO: Dont' think I should be setting the driver?
        self.set_driver(driver, myint(value), 56)
        # The set_alarm param is without the '_alarm' prefix
        self.params['alarm_'+param] = myint(value)
        return True

    def _set_misc_param(self, driver=None, param=None, **kwargs):
        value = kwargs.get("value")
        if value is None:
            self.parent.send_error("_set_misc_param not passed a value for driver %s: %s" % (driver, value) )
            return False
        # TODO: Should use the _driver specified function instead of int.
        if not self._set_misc_params({ param: int(value)}):
            self.parent.send_error("_set_misc_param failed to set %s=%s" % (param,value) )
        # TODO: Dont' think I should be setting the driver?
        self.set_driver(driver, myint(value), 56)
        # The set_misc param
        self.params[param] = myint(value)
        return True

    def _reboot(self, **kwargs):
        """ Reboot the Camera """
        return self._http_get("reboot.cgi",{})

    def _set_irled(self, **kwargs):
        """ Set the irled off=94 on=95 """
        value = kwargs.get("value")
        if value is None:
            self.parent.send_error("_set_irled not passed a value: %s" % (value) )
            return False
        if value == 0:
            dvalue = 94
        else:
            dvalue = 95
        if self._decoder_control( { 'command': dvalue} ):
            # TODO: Not storing this cause the camera doesn't allow us to query it.
            #self.set_driver("GVxx", myint(value), 56)
            return True
        self.parent.send_error("_set_irled failed to set %s" % (dvalue) )
        return False

    def _set_authm(self, **kwargs):
        """ Set the auth mode 0=Basic 1=Digest """
        value = kwargs.get("value")
        if value is None:
            self.parent.send_error("_set_authm not passed a value: %s" % (value) )
            return False
        self.auth_mode = int(value)
        self.parent.logger.debug("FoscamMJPEG:set_authm: %s",self.auth_mode)
        self.set_driver("GV10", self.auth_mode, 25)
        # Since they changed auth mode, make sure it works.
        self.query()
        self.motion.query()
        return True

    def _goto_preset(self, **kwargs):
        """ Goto the specified preset. 
              Preset 1 = Command 31
              Preset 2 = Command 33
              Preset 3 = Command 35
              Preset 16 = Command 61
              Preset 32 = Command 93
            So command is ((value * 2) + 29)
        """
        value = kwargs.get("value")
        if value is None:
            self.parent.send_error("_goto_preset not passed a value: %s" % (value) )
            return False
        value * 2 + 29
        value = myint((value * 2) + 29)
        if not self._decoder_control( { 'command': value} ):
            self.parent.send_error("_goto_preset failed to set %s" % (value) )
        return True

    _drivers = {
        'GV1': [0, 56, myfloat],
        'GV2': [0, 56, myint],
        'GV3': [0, 56, myint],
        'GV4': [0, 2,  myint],
        'GV5': [0, 25, myint],
        'GV6': [0, 2,  myint],
        'GV7': [0, 2,  myint],
        'GV8': [0, 25, myint],
        'GV9': [0, 2,  myint],
        'GV10': [0, 25,  myint],
        'GV11': [0, 56,  myfloat],
        'GV12': [0, 56,  myfloat],
        'GV13': [0, 25,  myint],
    }
    """ Driver Details:
    GV1:  float:   Version of this code (Major)
    GV2:  unsigned integer: IP Address
    GV3:  integer: Port
    GV4:  integer: Responding
    GV5:  integer: Network LED Mode
    GV6:  integer: Alarm Motion Armed
    GV7:  integer: Alarm Send Mail
    GV8:  integer: Motion Sensitivity
    GV9:  integer: Motion Compenstation
    GV10; integer: Authorization Mode
    GV11: float:   Camera System Version
    GV12: float:   Version of this code (Minor)
    GV13; integer: Upload Interval
    """
    _commands = {
        'QUERY': query,
        'SET_IRLED': _set_irled,
        'SET_LEDM':  partial(_set_misc_param,  driver="GV5", param='led_mode'),
        'SET_ALMOA': partial(_set_alarm_param, driver="GV6", param='motion_armed'),
        'SET_ALML':  partial(_set_alarm_param, driver="GV7", param='motion_mail'),
        'SET_ALMOS': partial(_set_alarm_param, driver="GV8", param='motion_sensitivity'),
        'SET_ALMOC': partial(_set_alarm_param, driver="GV9", param='motion_compensation'),
        'SET_UPINT': partial(_set_alarm_param, driver="GV13", param='upload_interval'),
        'SET_AUTHM': _set_authm,
        'SET_POS':   _goto_preset,
        'REBOOT':    _reboot,
    }
    # The nodeDef id of this camers.
    node_def_id = 'FoscamMJPEG'
Пример #18
0
class PointTrack:

    # default constructor
    def __init__(self):
        self.__origTime = 0
        self.__tcc = TrackCoordConv()
        self.__speedAndAngle = Motion()
        self.__origSpeed = 0.0
        self.__origAcc = 0.0
        self.__minDt = 0
        self.__maxDt = 0
        self.__minX = 0.0
        self.__maxX = 0.0
        self.__npivots = 0

    # This logic was ported from C++ that internally uses seconds.
    def _toSec(self, timeIn) :
        if timeIn > VERIFY_MILLISECONDS :
            return timeIn / 1000
        return timeIn

    # Test for equivalence with another PointTrack object
    def same(self, other):
        if self.__npivots!=other.__npivots :
           return False
        if self.__npivots==0 : 
           return True
        if self.__origTime!=other.__origTime : 
           return False
        if self.__origSpeed!=other.__origSpeed or \
           self.__origAcc!=other.__origAcc : 
           return False
        if self.__tcc.same(other.__tcc) :
           return True
        return False

    # Make this object a deep copy of another PointTrack object
    def PointTrack_(self, other):
        self.__origTime = other.__origTime
        self.__tcc.TrackCoordConv_(other.__tcc)
        self.__speedAndAngle.Motion_(other.__speedAndAngle)
        self.__origSpeed = other.__origSpeed
        self.__origAcc = other.__origAcc
        self.__minDt = other.__minDt
        self.__maxDt = other.__maxDt
        self.__minX = other.__minX
        self.__maxX = other.__maxX
        self.__npivots = other.__npivots

    # returns True if object describes a meaningful motion
    def ok(self):
        return self.__npivots>0

    # number of pivots the object was constructed with
    def getNpivots(self):
        return self.__npivots

    # Complete the construction of the tracking object by computing the 
    # possible ranges of time and x coordinate.
    def _finishTrack(self):
        if self.__origAcc==0.0 and self.__origSpeed==0 :
           return
        self.__minX = self.__tcc.getXmin()
        self.__maxX = self.__tcc.getXmax()
        if self.__origAcc==0 :
           self.__maxDt = self.__maxX/self.__origSpeed
           self.__maxX = self.__maxDt*self.__origSpeed
           self.__minDt = -self.__maxDt
           self.__minX = -self.__maxX
        elif self.__origSpeed==0 :
           if self.__origAcc>0 :
              self.__maxDt = math.sqrt(self.__maxX/self.__origAcc)
              self.__maxX = self.__maxDt*self.__origAcc*self.__maxDt
              self.__minX = 0
           else :
              self.__minDt = -math.sqrt(self.__minX/self.__origAcc)
              self.__minX = self.__minDt*self.__origAcc*self.__minDt
              self.__maxX = 0
        elif self.__origAcc>0 :
           q = self.__origSpeed*self.__origSpeed+4*self.__maxX*self.__origAcc
           self.__maxDt = (math.sqrt(q)-self.__origSpeed) / (2*self.__origAcc)
           self.__maxX =  self.__origSpeed*self.__maxDt+ \
                          self.__maxDt*self.__origAcc*self.__maxDt
           q = self.__origSpeed*self.__origSpeed+4*self.__minX*self.__origAcc
           if q<0 :
              q = 0
           self.__minDt = (math.sqrt(q)-self.__origSpeed) / (2*self.__origAcc)
           self.__minX = self.__origSpeed*self.__minDt+ \
                         self.__minDt*self.__origAcc*self.__minDt
        else :
           q = self.__origSpeed*self.__origSpeed+4*self.__minX*self.__origAcc
           self.__minDt = (math.sqrt(q)-self.__origSpeed) / (2*self.__origAcc)
           self.__minX = self.__origSpeed*self.__minDt+ \
                         self.__minDt*self.__origAcc*self.__minDt
           q = self.__origSpeed*self.__origSpeed+4*self.__maxX*self.__origAcc
           if q<0 :
              q = 0
           self.__maxDt = (math.sqrt(q)-self.__origSpeed) / (2*self.__origAcc)
           self.__maxX =  self.__origSpeed*self.__maxDt+ \
                          self.__maxDt*self.__origAcc*self.__maxDt

    # Return the forward coordinate as a function of time displacement from
    # the origin time
    def xOfDt(self, dt) :
        if dt==0 :
           return 0
        if dt>=self.__maxDt :
           return self.__maxX
        if dt<=self.__minDt :
           return self.__minX
        return self.__origSpeed*dt+dt*self.__origAcc*dt

    # Return the time displacement from the origin as a function of
    # the forward coordinate 
    def dtOfX(self, x) :
        if x==0 :
           return 0
        if x>=self.__maxX :
           return self.__maxDt
        if x<=self.__minX :
           return self.__minDt
        if self.__origAcc==0.0 :
           return x/self.__origSpeed
        q = self.__origSpeed*self.__origSpeed+4*x*self.__origAcc
        if q>=0.0 :
           return (math.sqrt(q)-self.__origSpeed) / (2*self.__origAcc)
        elif self.__origAcc<0 :
           return self.__maxDt
        else : 
           return self.__minDt

    # Assuming the tracker is at the forward coordinate corresponding to the
    # specified time, returns the time at which the forward coordinate is
    # that plus the supplied displacement.
    def moveTime(self, time0_, dFwdKm) :
        time0 = self._toSec(time0_)
        dt = self.dtOfX(self.xOfDt(time0-self.__origTime)+dFwdKm)
        return self.__origTime+dt

    # Does the real work associated with initializing the object based on
    # a location, time, and motion.
    def _initPT(self, latLon0, time0, motion, otime) :
        if latLon0.lat<-90.0 or latLon0.lat>90.0 or \
           latLon0.lon<-180.0 or latLon0.lon>180.0 :
           return
        if motion.bearing<0.0 or motion.bearing>360.0 or \
           motion.speed<-0.16 or motion.speed>300.0 :
           return
        self.__speedAndAngle.Motion_(motion)
        self.__npivots = 1
        if motion.speed==0.0 :
           self.__tcc.latLonBearingInit_(latLon0, 90)
           self.__speedAndAngle.bearing = 270
           self.__origTime = otime
           return
        # km/s -> knots
        if self.__speedAndAngle.speed<0.0 :
           self.__speedAndAngle.speed = self.__speedAndAngle.speed*-1944.0
        if self.__speedAndAngle.bearing>180.0 :
           bearing = self.__speedAndAngle.bearing-180.0
        else :
           bearing = self.__speedAndAngle.bearing+180.0
        self.__tcc.latLonBearingInit_(latLon0, bearing)
        # kts -> km/sec
        self.__origSpeed = self.__speedAndAngle.speed/1944.0
        self.__origTime = time0
        if otime==self.__origTime :
           self._finishTrack()
           return
        self.__tcc.advanceOrig_(self.__origSpeed*(otime-self.__origTime))
        bearing = self.__tcc.getBearing()
        if bearing>180.0 :
           self.__speedAndAngle.bearing = bearing-180.0
        else :
           self.__speedAndAngle.bearing = bearing+180.0
        self.__origTime = otime
        self._finishTrack()

    # Public interface for initializing the object based on a location, time,
    # and motion, defaulting the origin time to the current time.
    def latLonMotionInit_(self, latLon0, time0_, motion) :
        time0 = self._toSec(time0_)
        self._initPT(latLon0, time0, motion, time.time())

    # Public interface for initializing the object based on a location, time,
    # and motion, setting the origin time to the supplied value.
    def latLonMotionOrigTimeInit_(self, latLon0, time0_, motion, otime_) :
        '''
        @summary: Public interface for initializing the object based on a
                  location, time, and motion, with separately specified
                  origin point for track coordinate system.
        @param latLon: LatLoonCoord object for location of feature at time0_
        @param time0_: Time at which feature is located at latLon0 in
                       either seconds or milliseconds.
        @param motion: Motion object describe movement of feature at time0_
        @param otime_: Time at which forward track coordinate is 0.0km
        '''
        time0 = self._toSec(time0_)
        otime = self._toSec(otime_)
        self._initPT(latLon0, time0, motion, otime)

    # Does the real work associated with initializing the object based on
    # two location-time pairs.
    def _initPT2(self, latLon1, time1, latLon2, time2, otime) :
        if latLon1.lat<-90.0 or latLon1.lat>90.0 or \
           latLon1.lon<-180.0 or latLon1.lon>180.0 :
           return
        if latLon2.lat<-90.0 or latLon2.lat>90.0 or \
           latLon2.lon<-180.0 or latLon2.lon>180.0 :
           return
        dt = time2-time1
        if dt==0 :
           return
        self.__npivots = 2
        if latLon1.lat==latLon2.lat and latLon1.lon==latLon2.lon :
           self.__tcc.latLonBearingInit_(latLon1, 90.0)
           self.__speedAndAngle.bearing = 270.0
           self.__origTime = otime
           return
        self.__tcc.twoLatLonTimeInit_(latLon1, time1, latLon2, time2)
        self.__origSpeed = (self.__tcc.fwdLeftKmOf(latLon2).fwd - \
                            self.__tcc.fwdLeftKmOf(latLon1).fwd)/dt
        if self.__origSpeed < 0 :
           self.__origSpeed = -self.__origSpeed
        self.__speedAndAngle.speed = 1944.0*self.__origSpeed
        bearing = self.__tcc.getBearing()
        if bearing>180.0 :
           self.__speedAndAngle.bearing = bearing-180.0
        else :
           self.__speedAndAngle.bearing = bearing+180.0
        if time2>time1 :
           self.__origTime = time2
        else :
           self.__origTime = time1
        if otime==self.__origTime :
            self._finishTrack()
            return
        self.__tcc.advanceOrig_(self.__origSpeed*(otime-self.__origTime))
        bearing = self.__tcc.getBearing()
        if bearing>180.0 :
           self.__speedAndAngle.bearing = bearing-180.0
        else :
           self.__speedAndAngle.bearing = bearing+180.0
        self.__origTime = otime
        self._finishTrack()

    # Public interface for initializing the object based on two location-time
    # pairs, defaulting the origin time to the current time.
    def twoLatLonInit_(self, latLon1, time1_, latLon2, time2_) :
        time1 = self._toSec(time1_)
        time2 = self._toSec(time2_)
        self._initPT2(latLon1, time1, latLon2, time2, time.time())

    # Public interface for initializing the object based on two location-time
    # pairs, setting the origin time to the supplied value.
    def twoLatLonOrigTimeInit_(self, latLon1, time1_, \
                                latLon2, time2_, otime_) :
        '''
        @summary: Public interface for initializing the object based on two
                  location-time pairs, with separately specified
                  origin point for track coordinate system.
        @param latLon1: LatLoonCoord object for location of feature at time1_
        @param time1_: Time at which feature is located at latLon1 in
                       either seconds or milliseconds.
        @param latLon2: LatLoonCoord object for location of feature at time2_
        @param time1_: Time at which feature is located at latLon2 in
                       either seconds or milliseconds.
        @param otime_: Time at which forward track coordinate is 0.0km
        '''
        time1 = self._toSec(time1_)
        time2 = self._toSec(time2_)
        otime = self._toSec(otime_)
        self._initPT2(latLon1, time1, latLon2, time2, otime)

    # Does the real work associated with initializing the object based on
    # three location-time pairs.
    def _initPT3(self, latLon1, time1, latLon2, time2, latLon3, time3, otime) :
        if latLon1.lat<-90.0 or latLon1.lat>90.0 or \
           latLon1.lon<-180.0 or latLon1.lon>180.0 :
           return
        if latLon2.lat<-90.0 or latLon2.lat>90.0 or \
           latLon2.lon<-180.0 or latLon2.lon>180.0 :
           return
        if latLon3.lat<-90.0 or latLon3.lat>90.0 or \
           latLon3.lon<-180.0 or latLon3.lon>180.0 :
           return
        if time1==time2 or time2==time3 or time1==time3 :
           return
        self.__tcc.threeLatLonTimeInit_( \
           latLon1, time1, latLon2, time2, latLon3, time3)
        if not self.__tcc.ok() :
           return
        if time3>time1 and time3>time2 :
           self.__origTime = time3
           dtA = time1-self.__origTime
           dxA = self.__tcc.fwdLeftKmOf(latLon1).fwd
           dtB = time2-self.__origTime
           dxB = self.__tcc.fwdLeftKmOf(latLon2).fwd
        elif time2>time1 and time2>time3 :
           self.__origTime = time2
           dtA = time1-self.__origTime
           dxA = self.__tcc.fwdLeftKmOf(latLon1).fwd
           dtB = time3-self.__origTime
           dxB = self.__tcc.fwdLeftKmOf(latLon3).fwd
        else :
           self.__origTime = time1
           dtA = time2-self.__origTime
           dxA = self.__tcc.fwdLeftKmOf(latLon2).fwd
           dtB = time3-self.__origTime
           dxB = self.__tcc.fwdLeftKmOf(latLon3).fwd
        if dxA/dtA==dxB/dtB :
           self.__origAcc = 0.0
           self.__origSpeed = dxA/dtA
        else :
           dt2A = dtA*dtA
           dt2B = dtB*dtB
           rrr = dt2A/dt2B
           self.__origSpeed = (dxA-dxB*rrr)/(dtA-dtB*rrr)
           self.__origAcc = (dxA-dtA*self.__origSpeed)/dt2A
        if otime!=self.__origTime :
           dt = otime-self.__origTime
           dx = self.__origSpeed*dt+dt*self.__origAcc*dt
           self.__tcc.advanceOrig_(dx)
           self.__origSpeed = self.__origSpeed+dt*self.__origAcc
           self.__origTime = otime
        self.__speedAndAngle.speed = 1944.0*self.__origSpeed
        bearing = self.__tcc.getBearing()
        if bearing>180.0 :
           self.__speedAndAngle.bearing = bearing-180.0
        else :
           self.__speedAndAngle.bearing = bearing+180.0
        self.__npivots = 3
        self._finishTrack()

    # Public interface for initializing the object based on three location-time
    # pairs, defaulting the origin time to the current time.
    def threeLatLonInit_(self, latLon1, time1_, latLon2, time2_, \
                         latLon3, time3_) :
        time1 = self._toSec(time1_)
        time2 = self._toSec(time2_)
        time3 = self._toSec(time3_)
        self._initPT3(latLon1, time1, latLon2, time2, \
                       latLon3, time3, time.time())

    # Public interface for initializing the object based on three location-time
    # pairs, setting the origin time to the supplied value.
    def threeLatLonOrigTimeInit_(self, latLon1, time1_, latLon2, time2_, \
                                  latLon3, time3_, otime_) :
        time1 = self._toSec(time1_)
        time2 = self._toSec(time2_)
        time3 = self._toSec(time3_)
        otime = self._toSec(otime_)
        self._initPT3(latLon1, time1, latLon2, time2, latLon3, time3, otime)

    # Returns LatLonCoord of the (0 fwd, 0 left) point track relative.
    def getOrigin(self) :
        return self.__tcc.getOrigin()

    # Returns the time at which the tracked object is at the origin.
    def PT_getOrigTime(self) :
        return self.__origTime

    # Returns the Motion associated with the origin point.
    def getSpeedAndAngle(self) :
        return self.__speedAndAngle

    # Returns the speed of movement associated with the origin point.
    def getOrigSpeed(self) :
        return self.__origSpeed

    # Returns the forward rate of acceleration associated with the origin point.
    def getOrigAcc(self) :
        return self.__origAcc

    # Returns the radius of curvature of the track associated with the
    # origin point.
    def getRadius(self) :
        return self.__tcc.getRadius()

    # Returns the minimum time displacement from the origin time that can be
    # unambiguously resolved.
    def getMinDt(self) :
        return self.__minDt

    # Returns the maximum time displacement from the origin time that can be
    # unambiguously resolved.
    def getMaxDt(self) :
        return self.__maxDt

    # Returns the time associated with the point half-way backward along the 
    # circle representing the track path.
    def getMinTime(self) :
        return self.__minDt+self.__origTime

    # Returns the time associated with the point half-way forward along the 
    # circle representing the track path.
    def getMaxTime(self) :
        return self.__maxDt+self.__origTime

    # Returns the minimum workable forward coordinate, which is half-way 
    # backward along the circle representing the track path.
    def getMinX(self) :
        return self.__minX

    # Returns the maximum workable forward coordinate, which is half-way 
    # forward along the circle representing the track path.
    def getMaxX(self) :
        return self.__maxX

    # Returns the TrackCoordConv object being used by this PointTrack object.
    def PT_getTCC(self) :
        return self.__tcc

    # Returns speed and bearing as a function of time, as a Motion object.
    def speedAndAngleOf(self, time0_) :
        '''
        @summary: Returns movement vector of point as a function of time.
        @param time0_: Time to compute movement of feature for, in
                       either seconds or milliseconds.
        @return: Movement vector of feature at time0_, as a Motion object.
        '''
        time0 = self._toSec(time0_)
        if self.__npivots==0 :
           return Motion(0,0)
        if time0==0 or time0==self.__origTime :
           return self.__speedAndAngle
        #dt = otime - self.__origTime
        dt = time0- self.__origTime
        if dt>self.__maxDt or dt<self.__minDt :
           return Motion(0,0)
        bearing = self.__tcc.bearingOf(self.xOfDt(dt))
        if bearing > 180.0 :
           bearing = bearing - 180.0
        else :
           bearing = bearing + 180.0
        return Motion((self.__origSpeed+self.__origAcc*dt)*1944.0, bearing)

    # returns lat/lon of point as a function of time, as a LatLonCoord object.
    def trackPoint(self, time0_) :
        '''
        @summary: Returns lat/lon of point as a function of time.
        @param time0_: Time to compute location of feature for, in
                       either seconds or milliseconds.
        @return: Location of feature at time0_, as a LatLonCoord object.
        '''
        time0 = self._toSec(time0_)
        if self.__npivots==0 :
           return LatLonCoord(1e12,1e12)
        return self.__tcc.latLonFrom(  \
                 self.xOfDt(time0-self.__origTime), 0)

    # computes the track relative coordinate of the point at the given time,
    # adds the supplied track relative offset (as TrackCoord object), and 
    # returns the lat/lon of that location.
    def offsetPointOf(self, time0_, fwdLeftKm) :
        time0 = self._toSec(time0_)
        if self.__npivots==0 :
           return LatLonCoord()
        return self.__tcc.latLonFrom( \
          self.xOfDt(time0-self.__origTime)+fwdLeftKm.fwd, fwdLeftKm.left)

    # computes the track relative coordinate of the point at the given time,
    # adds the supplied track relative offset coordinates, and returns the
    #  lat/lon of that location.
    def offsetPointFrom(self, time0_, fwdKm, leftKm) :
        time0 = self._toSec(time0_)
        if self.__npivots==0 :
           return LatLonCoord()
        return self.__tcc.latLonFrom( \
          self.xOfDt(time0-self.__origTime)+fwdKm, leftKm)

    # returns vector in track relative coordinates representing displacement
    # from location of point at given time to the supplied lat/lon, as a
    # TrackCoord object.
    def offsetKm(self, time0_, latLon) :
        time0 = self._toSec(time0_)
        if self.__npivots==0 :
           return TrackCoord()
        onetc = self.__tcc.fwdLeftKmOf(latLon)
        onetc.x = onetc.fwd-self.xOfDt(time0-self.__origTime)
        return onetc

    # If there is a time at which the input point is at the same track relative
    # forward coordinate as the object being tracked, return a list containing
    # that time and how far to the left of the track (negative is right) the
    # object is.  Otherwise return an empty list.
    def timeAndLeft(self, latLon) :
        if self.__npivots==0 or self.__origSpeed==0 and self.__origAcc==0 :
           return []
        fwdLft = self.__tcc.fwdLeftKmOf(latLon)
        if fwdLft.fwd<self.__minX or fwdLft.fwd>self.__maxX :
           return []
        return [ self.__origTime+self.dtOfX(fwdLft.fwd) , fwdLft.left ]

    # In the track coordinate system, return the vector displacement from the
    # first LatLonCoord object to the second.  Returned as a TrackCoord object
    # with units of kilometers.
    def doffsetKm(self, latLon0, latLon1) :
        onetc = self.__tcc.fwdLeftKmOf(latLon0)
        onetc.minus_(self.__tcc.fwdLeftKmOf(latLon1))
        return onetc

    # Returns a polygon that encloses the area swept out by the point over
    # the given range of time.  The arguments extendMin, extendMax, 
    # extendBck and extendFwd can be used to assign a 'footprint' to the
    # feature beyond a single point.  These arguments are all in kilometers.
    # extendMin is the size of the footprint left and right of the point at
    # at minTime, and extendMax is the size of the footprint left and right of
    # the point at maxTime.  extendBck extends the footprint behind the feature
    # extendFwd extends the footprint ahead of the feature.  If the path is
    # curved, enough points will be added along the direction of the movement
    # to describe the curved movement to the specified precision.
    def enclosedBy(self, minTime_, maxTime_, \
                      extendMin, extendMax, \
                      extendBck=0.0, extendFwd=0.0, \
                      precision=2.0) :
        minTime = self._toSec(minTime_)
        maxTime = self._toSec(maxTime_)
        if self.__npivots==0 or minTime>maxTime :
           return []
        if extendMin<=0.0 and extendMax<=0.0 or \
           extendBck<=0.0 and extendFwd<=0.0 and minTime==maxTime :
           return []
        if precision<1.0 :
           precision = 1.0
        if extendMin<0.0 :
           extendMin = 0.0
        if extendMax<0.0 :
           extendMax = 0.0
        if extendBck<0.0 :
           extendBck = 0.0
        if extendFwd<0.0 :
           extendFwd = 0.0
        n = 0
        oneRad = self.__tcc.getRadius()
        if oneRad!=0 :
           if oneRad<0 :
              oneRad = -oneRad
           stepdx = math.sqrt(8*precision*oneRad)
           alldx = extendBck + extendFwd + \
                   self.xOfDt(maxTime-self.__origTime) - \
                   self.xOfDt(minTime-self.__origTime)
           if stepdx<alldx :
              n = int(alldx/stepdx)
        retPoly = []
        retPoly.append(self.offsetPointFrom(maxTime, extendFwd, extendMax))
        retPoly.append(self.offsetPointFrom(maxTime, extendFwd, -extendMax))
        if n>0 :
           i = 0
           while i < n:
               wmin = (i+1.0)/(n+1.0)
               wmax = 1.0-wmin
               i = i+1
               extnow = extendMax*wmax+extendMin*wmin
               tnow = maxTime*wmax+minTime*wmin
               retPoly.append(self.offsetPointFrom(tnow, 0, -extnow))
        retPoly.append(self.offsetPointFrom(minTime, -extendBck, -extendMin))
        retPoly.append(self.offsetPointFrom(minTime, -extendBck, extendMin))
        if n>0 :
           i = 0
           while i < n:
               wmax = (i+1.0)/(n+1.0)
               wmin = 1.0-wmax
               i = i+1
               extnow = extendMax*wmax+extendMin*wmin
               tnow = maxTime*wmax+minTime*wmin
               retPoly.append(self.offsetPointFrom(tnow, 0, extnow))
        return retPoly

    # Returns a polygon that encloses the area swept out by the point over
    # the given range of time, assuming a default size 'footprint' of the
    # point.
    def polygonDef(self, minTime_, maxTime_) :
        '''
        @summary: Returns a polygon that encloses the area swept out by the
                  feature over the given range of time, assuming a default
                  assuming a default size 'footprint' of the tracked point.
        @param minTime_: Start of time range; either seconds or milliseconds.
        @param maxTime_: End of time range; either seconds or milliseconds.
        @return: A list of LatLonCoord objects describing the area swept.
        '''
        minTime = self._toSec(minTime_)
        maxTime = self._toSec(maxTime_)
        extendMin = 10.0
        extendBck = extendMin
        extendMax = 10.0+(maxTime-minTime)*5.0/3600.0
        extendFwd = extendMax
        return self.enclosedBy(minTime, maxTime, extendMin, extendMax, \
                                  extendBck, extendFwd)

    # For all the locations of the tracked object between minTime and maxTime,
    # computes the time and distance/bearing of the closest approach to the
    # given location.  If the result of the computation is meaningful, a
    # list will be returned containing the following:
    #   Begining time of the closest approach (integer unix time in secs)
    #   Ending time of the closest approach (integer unix time in secs)
    #   Point on the tracked object of the closest approach (LatLonCoord)
    #   Track relative coordinate of point at closest approach (TrackCoord)
    #   Distance to point at closest approach (float)
    #   Bearing to point at closest approach (float)
    # If the computation is not meaninful, will return empty list.
    def nearestOffset(self, latLon, minTime_, maxTime_) :
        minTime = self._toSec(minTime_)
        maxTime = self._toSec(maxTime_)
        if self.__npivots==0 or minTime>maxTime :
           return []
        timMin = self.getMinDt()
        timMax = self.getMaxDt()
        if minTime>timMax :
           maxTime = minTime
        elif maxTime<timMin :
           minTime = maxTime
        else :
           if maxTime>timMax :
              maxTime = timMax
           if minTime<timMin :
              minTime = timMin
        if minTime==maxTime :
           time0 = minTime
        else :
           talResult = self.timeAndLeft(latLon)
           if len(talResult) == 2 :
               time0 = talResult[0]
               if time0>maxTime :
                  time0 = maxTime
               elif time0<minTime :
                  time0 = minTime
           elif self.__tcc.fwdLeftKmOf(latLon).fwd >= 0 :
               time0 = maxTime
           else :
               time0 = minTime
        startTime = time0
        endTime = time0
        ontrack = self.trackPoint(time0)
        fwdLft =  self.offsetKm(time0, latLon)
        if latLon.lon==ontrack.lon :
           if latLon.lat==ontrack.lat :
              return [startTime, endTime, ontrack, TrackCoord(), 0.0, 0.0]
           if latLon.lat>=ontrack.lat :
              dist = (latLon.lat-ontrack.lat)*kmPerDegLat
              return [startTime, endTime, ontrack, fwdLft, dist, 0.0]
           dist = (ontrack.lat-latLon.lat)*kmPerDegLat
           return [startTime, endTime, ontrack, fwdLft, dist, 180.0]
        wrkTcc = TrackCoordConv()
        wrkTcc.twoLatLonInit_(latLon, ontrack)
        dist = -wrkTcc.fwdLeftKmOf(latLon).fwd
        bearing = wrkTcc.getBearing()
        if bearing<180.0 :
           bearing = bearing+180.0
        else :
           bearing = bearing-180.0
        return [startTime, endTime, ontrack, fwdLft, dist, bearing]