{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "import sys\n",
    "import csv\n",
    "import pvl\n",
    "\n",
    "import pandas as pd\n",
    "import numpy as np\n",
    "import math\n",
    "import pyproj\n",
    "from functools import singledispatch\n",
    "import warnings\n",
    "\n",
    "from plio.examples import get_path\n",
    "from plio.io.io_bae import read_gpf, read_ipf, read_atf\n",
    "from plio.utils.utils import find_in_dict\n",
    "from plio.spatial.transformations import *\n",
    "from collections import defaultdict\n",
    "import plio.io.io_controlnetwork as cn\n",
    "import plio.io.isis_serial_number as sn"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def socet2isis(at_file, cub_file_path, cub_ipf_map, target_name, outpath=None):\n",
    "    # Setup the at_file, path to cubes, and control network out path\n",
    "    at_file = at_file\n",
    "    cnet_out = os.path.split(os.path.splitext(at_file)[0])[1]\n",
    "    cub_path = cub_file_path\n",
    "\n",
    "    if(outpath):\n",
    "        outpath = outpath\n",
    "    else:\n",
    "        outpath = os.path.split(at_file)[0]\n",
    "\n",
    "    with open(cub_ipf_map) as cub_ipf_map:\n",
    "        reader = csv.reader(cub_ipf_map, delimiter = ',')\n",
    "        image_dict = dict([(row[0], row[1]) for row in reader])\n",
    "        \n",
    "    # Read in and setup the atf dict of information\n",
    "    atf_dict = read_atf(at_file)\n",
    "    \n",
    "    # Get the gpf and ipf files using atf dict\n",
    "    gpf_file = os.path.join(atf_dict['PATH'], atf_dict['GP_FILE']);\n",
    "    ipf_list = [os.path.join(atf_dict['PATH'], i) for i in atf_dict['IMAGE_IPF']]\n",
    "    \n",
    "    # Read in the gpf file and ipf file(s) into seperate dataframes\n",
    "    gpf_df = read_gpf(gpf_file)\n",
    "    ipf_df = read_ipf(ipf_list)\n",
    "\n",
    "    # Check for differences between point ids using each dataframes\n",
    "    # point ids as a reference\n",
    "    gpf_pt_idx = pd.Index(pd.unique(gpf_df['point_id']))\n",
    "    ipf_pt_idx = pd.Index(pd.unique(ipf_df['pt_id']))\n",
    "\n",
    "    point_diff = ipf_pt_idx.difference(gpf_pt_idx)\n",
    "\n",
    "    if len(point_diff) != 0:\n",
    "        warnings.warn(\"The following points found in ipf files missing from gpf file: \\n\\n{}. \\\n",
    "                      \\n\\nContinuing, but these points will be missing from the control network\".format(list(point_diff)))\n",
    "        \n",
    "    # Merge the two dataframes on their point id columns\n",
    "    socet_df = ipf_df.merge(gpf_df, left_on='pt_id', right_on='point_id')\n",
    "    \n",
    "    # Apply the transformations\n",
    "    apply_transformations(atf_dict, socet_df)\n",
    "    \n",
    "    # Define column remap for socet dataframe\n",
    "    column_map = {'pt_id': 'id', 'l.': 'y', 's.': 'x',\n",
    "                  'res_l': 'lineResidual', 'res_s': 'sampleResidual', 'known': 'Type',\n",
    "                  'lat_Y_North': 'aprioriY', 'long_X_East': 'aprioriX', 'ht': 'aprioriZ',\n",
    "                  'sig0': 'aprioriLatitudeSigma', 'sig1': 'aprioriLongitudeSigma', 'sig2': 'aprioriRadiusSigma',\n",
    "                  'sig_l': 'linesigma', 'sig_s': 'samplesigma'}\n",
    "    \n",
    "    # Rename the columns using the column remap above\n",
    "    socet_df.rename(columns = column_map, inplace=True)\n",
    "    \n",
    "    serial_dict = serial_numbers(image_dict, cub_path)\n",
    "\n",
    "    # creates the control network\n",
    "    cn.to_isis(os.path.join(outpath, cnet_out + '.net'), socet_df, serial_dict, targetname = targetname)\n",
    "    return socet_df"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "# Setup stuffs for the cub information namely the path and extension\n",
    "cub_path = '/Volumes/Blueman/'\n",
    "targetname = 'Mars'\n",
    "cub_map = '/Users/adampaquette/repos/plio/plio/examples/SocetSet/cub_map2.csv'\n",
    "\n",
    "# Path to atf file\n",
    "atf_file = ('/Users/adampaquette/repos/plio/plio/examples/SocetSet/Relative.atf')\n",
    "\n",
    "socet_df = socet2isis(atf_file, cub_path, cub_map, targetname)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def reverse_known(record):\n",
    "    \"\"\"\n",
    "    Converts the known field from a socet dataframe into the\n",
    "    isis point_type column\n",
    "\n",
    "    Parameters\n",
    "    ----------\n",
    "    record : object\n",
    "             Pandas series object\n",
    "\n",
    "    Returns\n",
    "    -------\n",
    "    : str\n",
    "      String representation of a known field\n",
    "    \"\"\"\n",
    "    record_type = record['known']\n",
    "    if record_type == 0 or record_type == 2:\n",
    "        return 0\n",
    "\n",
    "    elif record_type == 1 or record_type == 3 or record_type == 4:\n",
    "        return 3\n",
    "    \n",
    "def lat_socet_coord(record, semi_major, semi_minor):\n",
    "    \"\"\"\n",
    "    Function to convert lat_Y_North to ISIS_lat\n",
    "\n",
    "    Parameters\n",
    "    ----------\n",
    "    record : object\n",
    "             Pandas series object\n",
    "\n",
    "    semi_major : float\n",
    "                 Radius from the center of the body to the equater\n",
    "\n",
    "    semi_minor : float\n",
    "                 Radius from the pole to the center of mass\n",
    "\n",
    "    Returns\n",
    "    -------\n",
    "    coord_360 : float\n",
    "                Converted latitude into ocentric space, and mapped\n",
    "                into 0 to 360\n",
    "    \"\"\"\n",
    "    ographic_coord = oc2og(record['lat_Y_North'], semi_major, semi_minor)\n",
    "    return ((ographic_coord + 180) % 360) - 180\n",
    "\n",
    "def lon_socet_coord(record, semi_major, semi_minor):\n",
    "    \"\"\"\n",
    "    Function to convert lat_Y_North to ISIS_lat\n",
    "\n",
    "    Parameters\n",
    "    ----------\n",
    "    record : object\n",
    "             Pandas series object\n",
    "\n",
    "    semi_major : float\n",
    "                 Radius from the center of the body to the equater\n",
    "\n",
    "    semi_minor : float\n",
    "                 Radius from the pole to the center of mass\n",
    "\n",
    "    Returns\n",
    "    -------\n",
    "    coord_360 : float\n",
    "                Converted latitude into ocentric space, and mapped\n",
    "                into 0 to 360\n",
    "    \"\"\"\n",
    "    ographic_coord = oc2og(record['long_X_East'], semi_major, semi_minor)\n",
    "    return ((ographic_coord + 180) % 360) - 180\n",
    "\n",
    "def fix_sample_line(record, serial_dict, extension, cub_path):\n",
    "    # Cube location to load\n",
    "    cube = pvl.load(os.path.join(cub_path, serial_dict[record['serialnumber']] + extension))\n",
    "    line_size = find_in_dict(cube, 'Lines')\n",
    "    sample_size = find_in_dict(cube, 'Samples')\n",
    "\n",
    "    new_line = record['l.'] - (int(line_size)/2.0) - 1\n",
    "    new_sample = record['s.'] - (int(sample_size)/2.0) - 1\n",
    "    return new_line, new_sample\n",
    "\n",
    "def ignore_toggle(record):\n",
    "    if record['stat'] == True:\n",
    "        return 0\n",
    "    else:\n",
    "        return 1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "scrolled": false
   },
   "outputs": [],
   "source": [
    "return_df = cn.from_isis(\"/Users/adampaquette/repos/plio/plio/examples/SocetSet/Relative.net\")\n",
    "\n",
    "eRadius = 3.39619000000000e+006\n",
    "pRadius = eRadius * (1 - 1.08339143554195e-001)\n",
    "\n",
    "adjusted_flag = False\n",
    "\n",
    "cub_path = '/Volumes/Blueman/'\n",
    "extension = '.8bit.cub'\n",
    "cub_list = ['D06_029601_1846_XN_04N224W', \n",
    "            'F05_037684_1857_XN_05N224W']\n",
    "\n",
    "# \n",
    "cub_dict = {i: i + extension for i in cub_list}\n",
    "serial_dict = {sn.generate_serial_number(os.path.join(cub_path, i + extension)): i for i in cub_list}\n",
    "\n",
    "columns = []\n",
    "column_index = []\n",
    "\n",
    "for i, column in enumerate(list(return_df.columns)):\n",
    "    if column not in columns:\n",
    "        column_index.append(i)\n",
    "        columns.append(column)\n",
    "\n",
    "return_df = return_df.iloc[:, column_index]\n",
    "\n",
    "column_map = {'id': 'pt_id', 'line': 'l.', 'sample': 's.', \n",
    "              'lineResidual': 'res_l', 'sampleResidual': 'res_s', 'type': 'known', \n",
    "              'aprioriLatitudeSigma': 'sig0', 'aprioriLongitudeSigma': 'sig1', 'aprioriRadiusSigma': 'sig2', \n",
    "              'linesigma': 'sig_l', 'samplesigma': 'sig_s', 'ignore': 'stat'}\n",
    "\n",
    "if adjusted_flag:\n",
    "    column_map['adjustedY'] = 'lat_Y_North'\n",
    "    column_map['adjustedX'] = 'long_X_East'\n",
    "    column_map['adjustedZ'] = 'ht'\n",
    "else:\n",
    "    column_map['aprioriY'] = 'lat_Y_North'\n",
    "    column_map['aprioriX'] = 'long_X_East'\n",
    "    column_map['aprioriZ'] = 'ht'\n",
    "\n",
    "return_df.rename(columns = column_map, inplace=True)\n",
    "\n",
    "return_df['known'] = return_df.apply(reverse_known, axis = 1)\n",
    "return_df['ipf_file'] = return_df['serialnumber'].apply(lambda serial_number: serial_dict[serial_number])\n",
    "return_df['l.'], return_df['s.'] = zip(*return_df.apply(fix_sample_line, serial_dict = serial_dict, \n",
    "                                                                         extension = extension, \n",
    "                                                                         cub_path = cub_path, axis = 1))\n",
    "\n",
    "ecef = np.array([[return_df['long_X_East']], [return_df['lat_Y_North']], [return_df['ht']]])\n",
    "lla = body_fix(ecef, semi_major = eRadius, semi_minor = pRadius, inverse=True)\n",
    "return_df['long_X_East'], return_df['lat_Y_North'], return_df['ht'] = lla[0][0], lla[1][0], lla[2][0]\n",
    "\n",
    "return_df['lat_Y_North'] = return_df.apply(lat_socet_coord, semi_major=eRadius, semi_minor=pRadius, axis = 1)\n",
    "return_df['long_X_East'] = return_df.apply(lon_socet_coord, semi_major=eRadius, semi_minor=pRadius, axis = 1)\n",
    "\n",
    "return_df['stat'] = return_df.apply(ignore_toggle, axis = 1)\n",
    "return_df['val'] = return_df['stat']\n",
    "\n",
    "# Add dumby\n",
    "x_dummy = lambda x: np.full(len(return_df), x)\n",
    "\n",
    "return_df['sig0'] = x_dummy(0)\n",
    "return_df['sig1'] = x_dummy(0)\n",
    "return_df['sig2'] = x_dummy(0)\n",
    "\n",
    "return_df['res0'] = x_dummy(0)\n",
    "return_df['res1'] = x_dummy(0)\n",
    "return_df['res2'] = x_dummy(0)\n",
    "\n",
    "return_df['fid_x'] = x_dummy(0)\n",
    "return_df['fid_y'] = x_dummy(0)\n",
    "\n",
    "return_df['no_obs'] = x_dummy(1)\n",
    "return_df['fid_val'] = x_dummy(0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "return_df[['long_X_East', 'lat_Y_North', 'ht']].iloc[2]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "return_df[['long_X_East', 'lat_Y_North', 'ht']].iloc[2]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}