Code covered by the BSD License  

Highlights from
CTMSIM - an interactive freeway traffic macrosimulator

image thumbnail
from CTMSIM - an interactive freeway traffic macrosimulator by Alex Kurzhanskiy
Freeway traffic simulation based on Asymmetric Cell Transmission Model

fwcfgGUI(varargin)
function varargout = fwcfgGUI(varargin)
% FWCFGGUI M-file for fwcfgGUI.fig
%      FWCFGGUI, by itself, creates a new FWCFGGUI or raises the existing
%      singleton*.
%
%      H = FWCFGGUI returns the handle to a new FWCFGGUI or the handle to
%      the existing singleton*.
%
%      FWCFGGUI('Property','Value',...) creates a new FWCFGGUI using the
%      given property value pairs. Unrecognized properties are passed via
%      varargin to fwcfgGUI_OpeningFcn.  This calling syntax produces a
%      warning when there is an existing singleton*.
%
%      FWCFGGUI('CALLBACK') and FWCFGGUI('CALLBACK',hObject,...) call the
%      local function named CALLBACK in FWCFGGUI.M with the given input
%      arguments.
%
%      *See GUI Options on GUIDE's Tools menu.  Choose "GUI allows only one
%      instance to run (singleton)".
%
% See also: GUIDE, GUIDATA, GUIHANDLES

% Edit the above text to modify the response to help fwcfgGUI

% Last Modified by GUIDE v2.5 23-Feb-2008 20:23:00

% Begin initialization code - DO NOT EDIT
gui_Singleton = 1;
gui_State = struct('gui_Name',       mfilename, ...
                   'gui_Singleton',  gui_Singleton, ...
                   'gui_OpeningFcn', @fwcfgGUI_OpeningFcn, ...
                   'gui_OutputFcn',  @fwcfgGUI_OutputFcn, ...
                   'gui_LayoutFcn',  [], ...
                   'gui_Callback',   []);
if nargin & isstr(varargin{1})
    gui_State.gui_Callback = str2func(varargin{1});
end

if nargout
    [varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
else
    gui_mainfcn(gui_State, varargin{:});
end
% End initialization code - DO NOT EDIT


% --- Executes just before fwcfgGUI is made visible.
function fwcfgGUI_OpeningFcn(hObject, eventdata, handles, varargin)
% This function has no output args, see OutputFcn.
% hObject    handle to figure
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
% varargin   unrecognized PropertyName/PropertyValue pairs from the
%            command line (see VARARGIN)

% Choose default command line output for fwcfgGUI
handles.output = hObject;

% Update handles structure
guidata(hObject, handles);

% UIWAIT makes fwcfgGUI wait for user response (see UIRESUME)
% uiwait(handles.figure1);

global g_fwcfg;

if isstruct(g_fwcfg) & isfield(g_fwcfg, 'configFile')
  load(g_fwcfg.configFile);
end

if ~exist('defaultCell', 'var')
  defaultCell = l_defaultcell;
end
g_fwcfg.defaultCell = defaultCell;

if ~exist('freeway', 'var')
  freeway = 'Freeway';
end
g_fwcfg.freeway = freeway;

if ~exist('celldata', 'var')
  celldata = [];
end
if isempty(celldata)
  celldata = l_edit2cell(g_fwcfg.defaultCell, 0, 1);
end
g_fwcfg.cellData = adjust_cell_struct(celldata);

if g_fwcfg.cellData(1).PMstart > g_fwcfg.cellData(1).PMend
  g_fwcfg.direction = -1;
else
  g_fwcfg.direction = 1;
end
g_fwcfg.cellIndex   = 1;
g_fwcfg.currentCell = l_cell2edit(g_fwcfg.cellData(g_fwcfg.cellIndex));
g_fwcfg.isSaved     = 1;
g_fwcfg.isBusy      = 0;

l_createCellList(handles);
l_displayAll(handles);

return;



% --- Outputs from this function are returned to the command line.
function varargout = fwcfgGUI_OutputFcn(hObject, eventdata, handles)
% varargout  cell array for returning output args (see VARARGOUT);
% hObject    handle to figure
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Get default command line output from handles structure
varargout{1} = handles.output;

return;





% --------------------------------------------------------------------
% Menu functions: File, Edit
% --------------------------------------------------------------------

%%% FILE %%%
function menuFile_Callback(hObject, eventdata, handles)
return;

% New
function menuFileNew_Callback(hObject, eventdata, handles)
global g_fwcfg;

if g_fwcfg.isBusy
  beep;
  return;
end

if ~g_fwcfg.isSaved
  currFig  = get(0, 'CurrentFigure');
  pos_size = get(currFig, 'Position');
  res      = save_dialog([pos_size(1)+pos_size(3)/2.5 pos_size(2)+pos_size(4)/2.5], 'Save configuration?');
  if res == 1  % save configuration
    fn = uiputfile('*.mat');
    if ~isa(fn, 'double')
      save_config(g_fwcfg, fn);
    end
  elseif res == 2
    return;
  end
end

g_fwcfg.configFile  = [];
g_fwcfg.defaultCell = l_defaultcell;
g_fwcfg.freeway     = 'Freeway';
g_fwcfg.cellData    = l_edit2cell(g_fwcfg.defaultCell, 0, 1);
g_fwcfg.currentCell = l_cell2edit(g_fwcfg.cellData(g_fwcfg.cellIndex));
g_fwcfg.cellIndex   = 1;
g_fwcfg.direction   = 1;
g_fwcfg.isSaved     = 1;

l_createCellList(handles);
l_displayAll(handles);

return;


% Load
function menuFileLoad_Callback(hObject, eventdata, handles)
global g_fwcfg;

if g_fwcfg.isBusy
  beep;
  return;
end

if ~g_fwcfg.isSaved
  currFig  = get(0, 'CurrentFigure');
  pos_size = get(currFig, 'Position');
  res      = save_dialog([pos_size(1)+pos_size(3)/2.5 pos_size(2)+pos_size(4)/2.5], 'Save configuration?');
  if res == 1  % save configuration
    fn = uiputfile('*.mat');
    if ~isa(fn, 'double')
      save_config(g_fwcfg, fn);
    end
  elseif res == 2
    return;
  end
end

fn = uigetfile('*.mat');
if ~isa(fn, 'double')
  g_fwcfg.configFile = fn;
  load(fn);

  if ~exist('defaultCell', 'var')
    defaultCell = l_defaultcell;
  end
  g_fwcfg.defaultCell = defaultCell;

  if ~exist('freeway', 'var')
    freeway = 'Freeway';
  end
  g_fwcfg.freeway = freeway;

  if ~exist('celldata', 'var')
    celldata = [];
  end
  if isempty(celldata)
    celldata = l_edit2cell(g_fwcfg.defaultCell, 0, 1);
  end
  g_fwcfg.cellData = adjust_cell_struct(celldata);

  if g_fwcfg.cellData(1).PMstart > g_fwcfg.cellData(1).PMend
    g_fwcfg.direction = -1;
  else
    g_fwcfg.direction = 1;
  end
  g_fwcfg.cellIndex   = 1;
  g_fwcfg.currentCell = l_cell2edit(g_fwcfg.cellData(g_fwcfg.cellIndex));
  g_fwcfg.isSaved     = 1;

  l_createCellList(handles);
  l_displayAll(handles);
end

return;


% Save
function menuFileSave_Callback(hObject, eventdata, handles)
global g_fwcfg;

if g_fwcfg.isBusy
  beep;
  return;
end

fn = uiputfile('*.mat');
if ~isa(fn, 'double')
  save_config(g_fwcfg, fn);
  g_fwcfg.isSaved = 1;
end

return;


% Exit
function menuFileExit_Callback(hObject, eventdata, handles)
global g_fwcfg;

if g_fwcfg.isBusy
  beep;
  return;
end

fwcfgGUIclose;

return;



%%% EDIT %%%
function menuEdit_Callback(hObject, eventdata, handles)
return;

% Default Values
function menuEditDefault_Callback(hObject, eventdata, handles)
global g_fwcfg;

if g_fwcfg.isBusy
  beep;
  return;
end

g_fwcfg.isBusy = 1;
dfltGUI;

return;





% --------------------------------------------------------------------
% 'Global' parameters
% --------------------------------------------------------------------

% Freeway Name
function fwName_CreateFcn(hObject, eventdata, handles)
return;
function fwName_Callback(hObject, eventdata, handles)
global g_fwcfg;

g_fwcfg.isSaved = 0;
g_fwcfg.freeway = get(hObject, 'String');

return;


% Direction: Left to Right or Right to Left
function direction_CreateFcn(hObject, eventdata, handles)
return;
function direction_Callback(hObject, eventdata, handles)
global g_fwcfg;

g_fwcfg.isSaved = 0;

if get(hObject, 'Value') == 2
  g_fwcfg.direction = -1;
else
  g_fwcfg.direction = 1;
end
pms                 = str2double(get(handles.pmStart, 'String'));
g_fwcfg.cellData    = assign_pm(g_fwcfg.cellData, pms, g_fwcfg.direction);
g_fwcfg.currentCell = l_cell2edit(g_fwcfg.cellData(g_fwcfg.cellIndex));

l_displayAll(handles);

return;


% Starting Post Mile
function pmStart_CreateFcn(hObject, eventdata, handles)
return;
function pmStart_Callback(hObject, eventdata, handles)
global g_fwcfg;

g_fwcfg.isSaved = 0;

pms = str2double(get(hObject, 'String'));
if ~(pms >= 0)
  pms = g_fwcfg.cellData(1).PMstart;
end
g_fwcfg.cellData    = assign_pm(g_fwcfg.cellData, pms, g_fwcfg.direction);
g_fwcfg.currentCell = l_cell2edit(g_fwcfg.cellData(g_fwcfg.cellIndex));

l_displayAll(handles);

return;





% --------------------------------------------------------------------
% Cell parameters
% --------------------------------------------------------------------

% Cell length
function lengthTxt_CreateFcn(hObject, eventdata, handles)
return;
function lengthTxt_Callback(hObject, eventdata, handles)
global g_fwcfg;

g_fwcfg.isSaved = 0;

v = str2double(get(hObject, 'String'));
if ~(v >= 0)
  v = g_fwcfg.currentCell.length;
end
g_fwcfg.currentCell.length = v; %v/5280;
pms                        = str2double(get(handles.pmStart, 'String'));

g_fwcfg.cellData(g_fwcfg.cellIndex) = l_edit2cell(g_fwcfg.currentCell, ...
                                      g_fwcfg.cellData(g_fwcfg.cellIndex).PMstart, ...
                                      g_fwcfg.direction);
g_fwcfg.cellData                    = assign_pm(g_fwcfg.cellData, ...
                                                pms, ...
                                                g_fwcfg.direction);

l_displayAll(handles);

return;


% Number of lanes
function lanesTxt_CreateFcn(hObject, eventdata, handles)
return;
function lanesTxt_Callback(hObject, eventdata, handles)
global g_fwcfg;

g_fwcfg.isSaved = 0;

v = str2double(get(hObject, 'String'));
if ~(v >= 1) | (v > 10)
  v = g_fwcfg.currentCell.lanes;
end
g_fwcfg.currentCell.lanes = v;

g_fwcfg.cellData(g_fwcfg.cellIndex) = l_edit2cell(g_fwcfg.currentCell, ...
                                      g_fwcfg.cellData(g_fwcfg.cellIndex).PMstart, ...
                                      g_fwcfg.direction);

l_displayAll(handles);

return;


% Number of auxiliary lanes
function auxlanesTxt_CreateFcn(hObject, eventdata, handles)
return;
function auxlanesTxt_Callback(hObject, eventdata, handles)
global g_fwcfg;

g_fwcfg.isSaved = 0;

v = str2double(get(hObject, 'String'));
if ~(v >= 0) | (v > 3)
  v = g_fwcfg.currentCell.auxlanes;
end
g_fwcfg.currentCell.auxlanes = v;

g_fwcfg.cellData(g_fwcfg.cellIndex) = l_edit2cell(g_fwcfg.currentCell, ...
                                      g_fwcfg.cellData(g_fwcfg.cellIndex).PMstart, ...
                                      g_fwcfg.direction);

l_displayAll(handles);

return;


% Max flow
function fmaxTxt_CreateFcn(hObject, eventdata, handles)
return;
function fmaxTxt_Callback(hObject, eventdata, handles)
global g_fwcfg;

g_fwcfg.isSaved = 0;

v = str2double(get(hObject, 'String'));
if ~(v >= 0)
  v = g_fwcfg.currentCell.FDfmax;
end
g_fwcfg.currentCell.FDfmax = v;

g_fwcfg.cellData(g_fwcfg.cellIndex) = l_edit2cell(g_fwcfg.currentCell, ...
                                      g_fwcfg.cellData(g_fwcfg.cellIndex).PMstart, ...
                                      g_fwcfg.direction);

l_displayCell(handles);

return;


% Critical density
function rhocritTxt_CreateFcn(hObject, eventdata, handles)
return;
function rhocritTxt_Callback(hObject, eventdata, handles)
global g_fwcfg;

g_fwcfg.isSaved = 0;

v = str2double(get(hObject, 'String'));
if ~(v >= 0) | (v > g_fwcfg.currentCell.FDrhojam)
  v = g_fwcfg.currentCell.FDrhocrit;
end
g_fwcfg.currentCell.FDrhocrit = v;

g_fwcfg.cellData(g_fwcfg.cellIndex) = l_edit2cell(g_fwcfg.currentCell, ...
                                      g_fwcfg.cellData(g_fwcfg.cellIndex).PMstart, ...
                                      g_fwcfg.direction);

l_displayCell(handles);

return;


% Jam density
function rhojamTxt_CreateFcn(hObject, eventdata, handles)
return;
function rhojamTxt_Callback(hObject, eventdata, handles)
global g_fwcfg;

g_fwcfg.isSaved = 0;

v = str2double(get(hObject, 'String'));
if ~(v >= g_fwcfg.currentCell.FDrhocrit)
  v = g_fwcfg.currentCell.FDrhojam;
end
g_fwcfg.currentCell.FDrhojam = v;

g_fwcfg.cellData(g_fwcfg.cellIndex) = l_edit2cell(g_fwcfg.currentCell, ...
                                      g_fwcfg.cellData(g_fwcfg.cellIndex).PMstart, ...
                                      g_fwcfg.direction);

l_displayCell(handles);

return;


% Free-flow speed
function vfTxt_CreateFcn(hObject, eventdata, handles)
return;
function vfTxt_Callback(hObject, eventdata, handles)
global g_fwcfg;

g_fwcfg.isSaved = 0;

v = str2double(get(hObject, 'String'));
if ~(v > 0)
  v = g_fwcfg.currentCell.FDfmax / g_fwcfg.currentCell.FDrhocrit;
end
g_fwcfg.currentCell.FDrhocrit = g_fwcfg.currentCell.FDfmax / v;

g_fwcfg.cellData(g_fwcfg.cellIndex) = l_edit2cell(g_fwcfg.currentCell, ...
                                      g_fwcfg.cellData(g_fwcfg.cellIndex).PMstart, ...
                                      g_fwcfg.direction);

l_displayCell(handles);

return;


% Congestion wave speed
function wcTxt_CreateFcn(hObject, eventdata, handles)
return;
function wcTxt_Callback(hObject, eventdata, handles)
global g_fwcfg;

g_fwcfg.isSaved = 0;

v = str2double(get(hObject, 'String'));
if ~(v > 0)
  v = g_fwcfg.currentCell.FDfmax / ...
      (g_fwcfg.currentCell.FDrhojam - g_fwcfg.currentCell.FDrhocrit);
end
g_fwcfg.currentCell.FDrhojam = g_fwcfg.currentCell.FDrhocrit + ...
                               (g_fwcfg.currentCell.FDfmax / v);

g_fwcfg.cellData(g_fwcfg.cellIndex) = l_edit2cell(g_fwcfg.currentCell, ...
                                      g_fwcfg.cellData(g_fwcfg.cellIndex).PMstart, ...
                                      g_fwcfg.direction);

l_displayCell(handles);

return;


% On-ramp checkbox
function orCB_Callback(hObject, eventdata, handles)
global g_fwcfg;

g_fwcfg.isSaved = 0;

g_fwcfg.currentCell.OR              = get(hObject, 'Value');
g_fwcfg.cellData(g_fwcfg.cellIndex) = l_edit2cell(g_fwcfg.currentCell, ...
                                      g_fwcfg.cellData(g_fwcfg.cellIndex).PMstart, ...
                                      g_fwcfg.direction);


l_displayAll(handles);

return;


% Off-ramp checkbox
function frCB_Callback(hObject, eventdata, handles)
global g_fwcfg;

g_fwcfg.isSaved = 0;

g_fwcfg.currentCell.FR              = get(hObject, 'Value');
g_fwcfg.cellData(g_fwcfg.cellIndex) = l_edit2cell(g_fwcfg.currentCell, ...
                                      g_fwcfg.cellData(g_fwcfg.cellIndex).PMstart, ...
                                      g_fwcfg.direction);


l_displayAll(handles);

return;





% --------------------------------------------------------------------
% On-ramp parameters
% --------------------------------------------------------------------

% Name
function orNameTxt_CreateFcn(hObject, eventdata, handles)
return;
function orNameTxt_Callback(hObject, eventdata, handles)
global g_fwcfg;

g_fwcfg.isSaved = 0;

buf = get(hObject, 'String');
if isempty(buf)
  buf = g_fwcfg.currentCell.ORname;
end
g_fwcfg.currentCell.ORname = buf;

g_fwcfg.cellData(g_fwcfg.cellIndex) = l_edit2cell(g_fwcfg.currentCell, ...
                                      g_fwcfg.cellData(g_fwcfg.cellIndex).PMstart, ...
                                      g_fwcfg.direction);

return;


% Number of lanes
function orLanesTxt_CreateFcn(hObject, eventdata, handles)
return;
function orLanesTxt_Callback(hObject, eventdata, handles)
global g_fwcfg;

g_fwcfg.isSaved = 0;

v = str2double(get(hObject, 'String'));
if ~(v >= 1) | (v > 4)
  v = g_fwcfg.currentCell.ORlanes;
end
g_fwcfg.currentCell.ORlanes = v;

g_fwcfg.cellData(g_fwcfg.cellIndex) = l_edit2cell(g_fwcfg.currentCell, ...
                                      g_fwcfg.cellData(g_fwcfg.cellIndex).PMstart, ...
                                      g_fwcfg.direction);

l_displayAll(handles);

return;


% Max flow
function orFmaxTxt_CreateFcn(hObject, eventdata, handles)
return;
function orFmaxTxt_Callback(hObject, eventdata, handles)
global g_fwcfg;

g_fwcfg.isSaved = 0;

v = str2double(get(hObject, 'String'));
if ~(v >= 0)
  v = g_fwcfg.currentCell.ORfmax;
end
g_fwcfg.currentCell.ORfmax = v;

g_fwcfg.cellData(g_fwcfg.cellIndex) = l_edit2cell(g_fwcfg.currentCell, ...
                                      g_fwcfg.cellData(g_fwcfg.cellIndex).PMstart, ...
                                      g_fwcfg.direction);

return;


% Queue size
function orQueueTxt_CreateFcn(hObject, eventdata, handles)
return;
function orQueueTxt_Callback(hObject, eventdata, handles)
global g_fwcfg;

g_fwcfg.isSaved = 0;

v = str2double(get(hObject, 'String'));
if ~(v >= 0)
  v = g_fwcfg.currentCell.ORqsize;
end
g_fwcfg.currentCell.ORqsize = v;

g_fwcfg.cellData(g_fwcfg.cellIndex) = l_edit2cell(g_fwcfg.currentCell, ...
                                      g_fwcfg.cellData(g_fwcfg.cellIndex).PMstart, ...
                                      g_fwcfg.direction);

return;


% Gamma
function orGammaTxt_CreateFcn(hObject, eventdata, handles)
return;
function orGammaTxt_Callback(hObject, eventdata, handles)
global g_fwcfg;

g_fwcfg.isSaved = 0;

v = str2double(get(hObject, 'String'));
if ~(v >= 0) | (v > 1)
  v = g_fwcfg.currentCell.ORgamma;
end
g_fwcfg.currentCell.ORgamma = v;

g_fwcfg.cellData(g_fwcfg.cellIndex) = l_edit2cell(g_fwcfg.currentCell, ...
                                      g_fwcfg.cellData(g_fwcfg.cellIndex).PMstart, ...
                                      g_fwcfg.direction);

return;


% Xi
function orXiTxt_CreateFcn(hObject, eventdata, handles)
return;
function orXiTxt_Callback(hObject, eventdata, handles)
global g_fwcfg;

g_fwcfg.isSaved = 0;

v = str2double(get(hObject, 'String'));
if ~(v >= 0) | (v > 1)
  v = g_fwcfg.currentCell.ORxi;
end
g_fwcfg.currentCell.ORxi = v;

g_fwcfg.cellData(g_fwcfg.cellIndex) = l_edit2cell(g_fwcfg.currentCell, ...
                                      g_fwcfg.cellData(g_fwcfg.cellIndex).PMstart, ...
                                      g_fwcfg.direction);

return;





% --------------------------------------------------------------------
% Off-ramp parameters
% --------------------------------------------------------------------

% Name
function frNameTxt_CreateFcn(hObject, eventdata, handles)
return;
function frNameTxt_Callback(hObject, eventdata, handles)
global g_fwcfg;

g_fwcfg.isSaved = 0;

buf = get(hObject, 'String');
if isempty(buf)
  buf = g_fwcfg.currentCell.FRname;
end
g_fwcfg.currentCell.FRname = buf;

g_fwcfg.cellData(g_fwcfg.cellIndex) = l_edit2cell(g_fwcfg.currentCell, ...
                                      g_fwcfg.cellData(g_fwcfg.cellIndex).PMstart, ...
                                      g_fwcfg.direction);

return;


% Number of lanes
function frLanesTxt_CreateFcn(hObject, eventdata, handles)
return;
function frLanesTxt_Callback(hObject, eventdata, handles)
global g_fwcfg;

g_fwcfg.isSaved = 0;

v = str2double(get(hObject, 'String'));
if ~(v >= 1) | (v > 4)
  v = g_fwcfg.currentCell.FRlanes;
end
g_fwcfg.currentCell.FRlanes = v;

g_fwcfg.cellData(g_fwcfg.cellIndex) = l_edit2cell(g_fwcfg.currentCell, ...
                                      g_fwcfg.cellData(g_fwcfg.cellIndex).PMstart, ...
                                      g_fwcfg.direction);

l_displayAll(handles);

return;


% Max flow
function frFmaxTxt_CreateFcn(hObject, eventdata, handles)
return;
function frFmaxTxt_Callback(hObject, eventdata, handles)
global g_fwcfg;

g_fwcfg.isSaved = 0;

v = str2double(get(hObject, 'String'));
if ~(v >= 0)
  v = g_fwcfg.currentCell.FRfmax;
end
g_fwcfg.currentCell.FRfmax = v;

g_fwcfg.cellData(g_fwcfg.cellIndex) = l_edit2cell(g_fwcfg.currentCell, ...
                                      g_fwcfg.cellData(g_fwcfg.cellIndex).PMstart, ...
                                      g_fwcfg.direction);

return;


% Split ratio
function frBetaTxt_CreateFcn(hObject, eventdata, handles)
return;
function frBetaTxt_Callback(hObject, eventdata, handles)
global g_fwcfg;

g_fwcfg.isSaved = 0;

v = str2double(get(hObject, 'String'));
if ~(v >= 0) | (v > 1)
  v = g_fwcfg.currentCell.FRbeta;
end
g_fwcfg.currentCell.FRbeta = v;

g_fwcfg.cellData(g_fwcfg.cellIndex) = l_edit2cell(g_fwcfg.currentCell, ...
                                      g_fwcfg.cellData(g_fwcfg.cellIndex).PMstart, ...
                                      g_fwcfg.direction);

return;





% --------------------------------------------------------------------
% Button functions
% --------------------------------------------------------------------

% Add cell
function addButton_Callback(hObject, eventdata, handles)
global g_fwcfg;

if g_fwcfg.isBusy
  beep;
  return;
end

g_fwcfg.isSaved     = 0;

N                   = size(g_fwcfg.cellData, 2);  % number of cells
pms                 = g_fwcfg.cellData(g_fwcfg.cellIndex).PMend;

g_fwcfg.cellIndex   = g_fwcfg.cellIndex + 1;
g_fwcfg.currentCell = g_fwcfg.defaultCell;
g_fwcfg.cellData    = [g_fwcfg.cellData(1:(g_fwcfg.cellIndex-1)) ...
                       l_edit2cell(g_fwcfg.currentCell, pms, g_fwcfg.direction) ...
                       g_fwcfg.cellData(g_fwcfg.cellIndex:N)];
g_fwcfg.cellData    = assign_pm(g_fwcfg.cellData, ...
                                str2double(get(handles.pmStart, 'String')), ...
                                g_fwcfg.direction);

l_createCellList(handles);
l_displayAll(handles);

return;


% Duplicate cell
function duplicateButton_Callback(hObject, eventdata, handles)
global g_fwcfg;

if g_fwcfg.isBusy
  beep;
  return;
end

g_fwcfg.isSaved     = 0;

N                   = size(g_fwcfg.cellData, 2);  % number of cells
pms                 = g_fwcfg.cellData(g_fwcfg.cellIndex).PMend;

g_fwcfg.cellIndex   = g_fwcfg.cellIndex + 1;
g_fwcfg.cellData    = [g_fwcfg.cellData(1:(g_fwcfg.cellIndex-1)) ...
                       l_edit2cell(g_fwcfg.currentCell, pms, g_fwcfg.direction) ...
                       g_fwcfg.cellData(g_fwcfg.cellIndex:N)];
g_fwcfg.cellData    = assign_pm(g_fwcfg.cellData, ...
                                str2double(get(handles.pmStart, 'String')), ...
                                g_fwcfg.direction);

l_createCellList(handles);
l_displayAll(handles);

return;


% Delete cell
function deleteButton_Callback(hObject, eventdata, handles)
global g_fwcfg;

if g_fwcfg.isBusy
  beep;
  return;
end

N = size(g_fwcfg.cellData, 2);  % number of cells
if N == 1
  beep;
  return;
end

g_fwcfg.isSaved = 0;

if g_fwcfg.cellIndex == N
  g_fwcfg.cellIndex = N - 1;
  g_fwcfg.cellData  = g_fwcfg.cellData(1:(N-1));
else
  g_fwcfg.cellData  = [g_fwcfg.cellData(1:(g_fwcfg.cellIndex-1)) ...
                       g_fwcfg.cellData((g_fwcfg.cellIndex+1):N)];
end

g_fwcfg.currentCell = l_cell2edit(g_fwcfg.cellData(g_fwcfg.cellIndex));
g_fwcfg.cellData    = assign_pm(g_fwcfg.cellData, ...
                                g_fwcfg.cellData(1).PMstart, ...
                                g_fwcfg.direction);

l_createCellList(handles);
l_displayAll(handles);

return;





% --------------------------------------------------------------------
% Cell list
% --------------------------------------------------------------------

function cellList_CreateFcn(hObject, eventdata, handles)
return;
function cellList_Callback(hObject, eventdata, handles)
global g_fwcfg;

g_fwcfg.cellIndex   = get(hObject, 'Value');
g_fwcfg.currentCell = l_cell2edit(g_fwcfg.cellData(g_fwcfg.cellIndex));
l_displayAll(handles);

return;





% --------------------------------------------------------------------
% Miscellaneous
% --------------------------------------------------------------------

function l_displayAll(handles)
% Display everything

global g_fwcfg;

l_displayGlobalParameters(handles);
l_displayCell(handles);

axes(handles.freeway)
plot_freeway(g_fwcfg.cellData);
hold on;
plot_fwselect(g_fwcfg.cellData, g_fwcfg.cellIndex, 1);
hold off;

axes(handles.fwcell);
plot_fwcell(g_fwcfg.cellData(g_fwcfg.cellIndex));

return;



function l_displayGlobalParameters(handles)
% Display global parameters

global g_fwcfg;

set(handles.fwName, 'String', g_fwcfg.freeway);
set(handles.pmStart, 'String', num2str(g_fwcfg.cellData(1).PMstart));
if g_fwcfg.direction < 0
  set(handles.direction, 'Value', 2);
else
  set(handles.direction, 'Value', 1);
end

return;



function l_displayCell(handles)
% Display selected cell

global g_fwcfg;

idx  = g_fwcfg.cellIndex;
cell = g_fwcfg.currentCell;

% cell box
set(handles.cellHeader, 'String', sprintf('Cell %d', idx));
set(handles.lengthTxt, 'String', num2str(cell.length));
set(handles.lanesTxt, 'String', num2str(cell.lanes));
set(handles.auxlanesTxt, 'String', num2str(cell.auxlanes));
set(handles.fmaxTxt, 'String', num2str(cell.FDfmax));
set(handles.rhocritTxt, 'String', num2str(cell.FDrhocrit));
set(handles.rhojamTxt, 'String', num2str(cell.FDrhojam));
set(handles.vfTxt, 'String', num2str(cell.FDfmax/cell.FDrhocrit));
set(handles.wcTxt, 'String', num2str(cell.FDfmax/(cell.FDrhojam-cell.FDrhocrit)));
set(handles.orCB, 'Value', cell.OR);
set(handles.frCB, 'Value', cell.FR);

% on-ramp box
set(handles.orNameTxt, 'String', cell.ORname);
set(handles.orLanesTxt, 'String', num2str(cell.ORlanes));
set(handles.orFmaxTxt, 'String', num2str(cell.ORfmax));
set(handles.orQueueTxt, 'String', num2str(cell.ORqsize));
set(handles.orGammaTxt, 'String', num2str(cell.ORgamma));
set(handles.orXiTxt, 'String', num2str(cell.ORxi));
l_orBoxEnDisable(handles, cell.OR);

% off-ramp box
set(handles.frNameTxt, 'String', cell.FRname);
set(handles.frLanesTxt, 'String', num2str(cell.FRlanes));
set(handles.frFmaxTxt, 'String', num2str(cell.FRfmax));
set(handles.frBetaTxt, 'String', num2str(cell.FRbeta));
l_frBoxEnDisable(handles, cell.FR);

% fundamental diagram
axes(handles.FD);
plot(1, 1, 'w');
hold on;
legend('Fundamental Diagram');
plot([0 cell.FDrhocrit], [0 cell.FDfmax], 'g', 'LineWidth', 2);
plot([cell.FDrhocrit cell.FDrhojam], [cell.FDfmax 0], 'r', 'LineWidth', 2);
plot([cell.FDrhocrit cell.FDrhojam], [cell.FDfmax 0], 'ko');
xlabel('Density (vpml)');
ylabel('Flow (vphl)');
hold off;

return;



function l_createCellList(handles)
% Create cell list

global g_fwcfg;

buf = [];
N   = size(g_fwcfg.cellData, 2);  % number of cells

for i = 1:N
  buf = strvcat(buf, sprintf('Cell %d', i));
end

if g_fwcfg.cellIndex > N
  g_fwcfg.cellIndex = N;
end

set(handles.cellList, 'String', buf);
set(handles.cellList, 'Value', g_fwcfg.cellIndex);

return;



function ic = l_cell2edit(cell)
% Convert normal cell structure into internal cell structure
global g_fwcfg;

% mainline
ic.length         = abs(cell.PMend - cell.PMstart);
ic.lanes          = floor(cell.lanes);
ic.auxlanes       = round((cell.lanes - ic.lanes) / 0.3);
ic.FDfmax         = cell.FDfmax / cell.lanes;  % vph per lane
ic.FDrhocrit      = cell.FDrhocrit / cell.lanes;  % vpm per lane
ic.FDrhojam       = cell.FDrhojam / cell.lanes;  % vpm per lane

% on-ramp
if ~isempty(cell.ORname)
  ic.OR             = 1;
  ic.ORname         = cell.ORname;
  ic.ORlanes        = cell.ORlanes;
  ic.ORfmax         = cell.ORfmax / cell.ORlanes;  % vph per lane
  ic.ORflow         = cell.ORflow / cell.ORlanes;  % vph per lane
  ic.ORqsize        = cell.ORqsize / cell.ORlanes;  % vehicles per lane
  ic.ORknob         = cell.ORknob;
  ic.ORmlcontroller = cell.ORmlcontroller;
  ic.ORqcontroller  = cell.ORqcontroller;
  ic.ORgamma        = cell.ORgamma;
  ic.ORxi           = cell.ORxi;
else
  ic.OR             = 0;
  ic.ORname         = g_fwcfg.defaultCell.ORname;
  ic.ORlanes        = g_fwcfg.defaultCell.ORlanes;
  ic.ORfmax         = g_fwcfg.defaultCell.ORfmax;
  ic.ORflow         = g_fwcfg.defaultCell.ORflow;
  ic.ORqsize        = g_fwcfg.defaultCell.ORqsize;
  ic.ORknob         = g_fwcfg.defaultCell.ORknob;
  ic.ORmlcontroller = g_fwcfg.defaultCell.ORmlcontroller;
  ic.ORqcontroller  = g_fwcfg.defaultCell.ORqcontroller;
  ic.ORgamma        = g_fwcfg.defaultCell.ORgamma;
  ic.ORxi           = g_fwcfg.defaultCell.ORxi;
end

% off-ramp
if ~isempty(cell.FRname)
  ic.FR      = 1;
  ic.FRname  = cell.FRname;
  ic.FRlanes = cell.FRlanes;
  ic.FRfmax  = cell.FRfmax / cell.FRlanes;  % vph per lane
  ic.FRbeta  = cell.FRbeta;
  ic.FRknob  = cell.FRknob;
else
  ic.FR      = 0;
  ic.FRname  = g_fwcfg.defaultCell.FRname;
  ic.FRlanes = g_fwcfg.defaultCell.FRlanes;
  ic.FRfmax  = g_fwcfg.defaultCell.FRfmax;
  ic.FRbeta  = g_fwcfg.defaultCell.FRbeta;
  ic.FRknob  = g_fwcfg.defaultCell.FRknob;
end

return;



function cell = l_edit2cell(ic, pmStart, direction)
% Convert internal cell structure into normal cell structure

% mainline
cell.PMstart        = pmStart;
cell.PMend          = pmStart  +  (direction * ic.length);
cell.lanes          = ic.lanes  +  (0.3 * ic.auxlanes);
cell.FDfmax         = ic.FDfmax * cell.lanes;
cell.FDrhocrit      = ic.FDrhocrit * cell.lanes;
cell.FDrhojam       = ic.FDrhojam * cell.lanes;

% on-ramp
if ic.OR
  cell.ORname         = ic.ORname;
  cell.ORlanes        = ic.ORlanes;
  cell.ORfmax         = ic.ORfmax * ic.ORlanes;
  cell.ORqsize        = ic.ORqsize * ic.ORlanes;
  cell.ORflow         = ic.ORflow * ic.ORlanes;
  cell.ORknob         = ic.ORknob;
  cell.ORmlcontroller = ic.ORmlcontroller;
  cell.ORqcontroller  = ic.ORqcontroller;
  cell.ORgamma        = ic.ORgamma;
  cell.ORxi           = ic.ORxi;
else
  cell.ORname         = [];
  cell.ORlanes        = 0;
  cell.ORfmax         = 0;
  cell.ORqsize        = 0;
  cell.ORflow         = 0;
  cell.ORknob         = 0;
  cell.ORmlcontroller = [];
  cell.ORqcontroller  = [];
  cell.ORgamma        = 0;
  cell.ORxi           = 0;
end

% off-ramp
if ic.FR
  cell.FRname         = ic.FRname;
  cell.FRlanes        = ic.FRlanes;
  cell.FRfmax         = ic.FRfmax * ic.FRlanes;
  cell.FRbeta         = ic.FRbeta;
  cell.FRknob         = ic.FRknob;
else
  cell.FRname         = [];
  cell.FRlanes        = 0;
  cell.FRfmax         = 0;
  cell.FRbeta         = 0;
  cell.FRknob         = 0;
end

return;



function l_orBoxEnDisable(handles, cmd)
% Enable or disable on-ramp box

if cmd
  buf = 'on';
else
  buf = 'off';
end

set(handles.orFrame, 'Visible', buf);
set(handles.orHeader, 'Visible', buf);
set(handles.orNameTag, 'Visible', buf);
set(handles.orNameTxt, 'Visible', buf);
set(handles.orLanesTag, 'Visible', buf);
set(handles.orLanesTxt, 'Visible', buf);
set(handles.orFmaxTag, 'Visible', buf);
set(handles.orFmaxTxt, 'Visible', buf);
set(handles.orQueueTag, 'Visible', buf);
set(handles.orQueueTxt, 'Visible', buf);
set(handles.orGammaTag, 'Visible', buf);
set(handles.orGammaTxt, 'Visible', buf);
set(handles.orXiTag, 'Visible', buf);
set(handles.orXiTxt, 'Visible', buf);

return;



function l_frBoxEnDisable(handles, cmd)
% Enable or disable off-ramp box

if cmd
  buf = 'on';
else
  buf = 'off';
end

set(handles.frFrame, 'Visible', buf);
set(handles.frHeader, 'Visible', buf);
set(handles.frNameTag, 'Visible', buf);
set(handles.frNameTxt, 'Visible', buf);
set(handles.frLanesTag, 'Visible', buf);
set(handles.frLanesTxt, 'Visible', buf);
set(handles.frFmaxTag, 'Visible', buf);
set(handles.frFmaxTxt, 'Visible', buf);
set(handles.frBetaTag, 'Visible', buf);
set(handles.frBetaTxt, 'Visible', buf);

return;



function dflt_cell = l_defaultcell()
% Generate default cell

dflt_cell.length         = 1;  % miles
dflt_cell.lanes          = 4;
dflt_cell.auxlanes       = 0;
dflt_cell.FDfmax         = 2200;  % vph per lane
dflt_cell.FDrhocrit      = 40;  % vpm per lane
dflt_cell.FDrhojam       = 200;  % vpm per lane
dflt_cell.OR             = 1;
dflt_cell.ORname         = 'On-ramp';
dflt_cell.ORlanes        = 1;
dflt_cell.ORfmax         = 600;  % vph per lane
dflt_cell.ORqsize        = 50;
dflt_cell.ORflow         = 0;
dflt_cell.ORknob         = 1;
dflt_cell.ORmlcontroller = [];
dflt_cell.ORqcontroller  = [];
dflt_cell.ORgamma        = 1;
dflt_cell.ORxi           = 1;
dflt_cell.FR             = 1;
dflt_cell.FRname         = 'Off-ramp';
dflt_cell.FRlanes        = 1;
dflt_cell.FRfmax         = 600;  % vph per lane;
dflt_cell.FRbeta         = 0.1;
dflt_cell.FRknob         = 1;

return;

Contact us at files@mathworks.com