ECE
417/617 Elements of
Software Engineering
|
|
Spring 2005
In this course students will learn to build high-quality, reliable, and
extensible software systems that are too large for a single programmer.
Emphasis is placed upon good programming practices (object-oriented design and
clean, well-documented code), teamwork skills (planning, communicating, and
interacting), and bringing the project to completion (testing and
verification). A semester-long project complements the theory with practice.
Syllabus
Week
| Topic
| Assignment
|
1
| introduction / overview |
hw#1 (1/21) |
2
| C++ and object-oriented programming |
quiz #1 (1/26); hw#2 (1/28) |
3
| More C++ |
milestone #1 (2/8) |
4
| Visual Studio IDE |
quiz #2 (2/11) |
5
| CVS and version control |
milestone #2 (2/18) |
6
| Agile methods and extreme programming |
quiz #3 (2/25) |
7
| Testing |
milestone #3 (3/4) |
8
| Requirements elicitation |
quiz #4 (3/11) |
9
| System design |
milestone #4 (3/16) |
10
| [Spring break] |
|
11
| UML |
milestone #5 (3/30) |
12
| User interfaces |
quiz #5 (4/8) |
13
| Life cycles |
milestone #6 (4/13) |
14
| Project management |
quiz #6 (4/22) |
15 | Ergonomics |
final system (4/27) |
Textbook:
Other recommended reading:
- Bjarne Stroustrup,
C++ Programming
Language, Addison-Wesley, 2000.
- Roger S. Pressman,
Software Engineering: A Practitioner's Approach, McGraw Hill, 2005.
- Frederick P. Brooks, Jr.,
The
Mythical Man-Month: Essays on Software Engineering, 2nd ed.,
Addison-Wesley, 1995.
- E. Gamma, R. Helm, R. Johnson, J. Vlissides,
Design Patterns:
Elements of Reusable Object-Oriented Software, Addison-Wesley, 1994.
- Martin Fowler,
UML Distilled: A
Brief Guide to the Standard Object Modeling Language, Addison-Wesley,
2003.
Additional software engineering resources
- Condensed Crash Course on C++
- An Intro to Concurrent Versions System (CVS)
- GUI-Based Programming
- System Design
- Brief Overview of UML Diagrams with a Simple
Example
- Design Patterns
- User Interface Design
- Software Life Cycles
- The Cathedral and the Bazaar:
A Look at Open-Source
- Repetitive Strain Injury (RSI)
A main part of the class is a semester-long project in which the entire class
participates. The project is
written in C++ using Microsoft's Visual C++ 6.0 integrated development
environment (IDE). The code is checked into a central repository using the
concurrent versions system (CVS). This semester the project is to develop an
end-user GUI-based application for detecting and tracking roots in minirhizotron
image sequences. Our client is
Dr. Christina
Wells and her lab in Horticulture. See the following documents for
further info: client's initial
project description and sample
spreadsheet output. Our goal is to develop an open-source application
that can be used by horticulture researchers beyond the end of the semester, the
code being released to the world under the GNU General Public License.
Project organization
Students are divided into groups, and the groups work in parallel to develop
rival applications that meet the desired specifications. Including the
final demo, there are seven biweekly milestones throughout the semester.
For each milestone, the job of each group is to write clean, maintainable code
that meets the specifications in a robust manner. The students are
initially divided randomly into groups of four people each, then they are
randomly reshuffled after Milestone#2 into new groups of four people each, then
after Milestone#5 they are randomly reshuffled again into groups of five people
each. Each milestone is treated like a public release, so that (because
this is an open-source project) each group is allowed to incorporate whatever
code it desires from any other group. For example, for Milestone#3, a
group may use code that other groups checked in for Milestone#2; in fact, a
group may scrap their entire code base completely and start with another group's
code, if they so desire. No code sharing, however, is allowed within a
single Milestone.
Each group is responsible for dividing up the work among its members, scoping
the work to be done, and keeping track of the accomplishments of each member as
well as the accuracy of the time estimates. For each milestone the group
should submit the source code itself (via CVS); a compiled executable (via
email); a system design document (hardcopy); and a summary of the work done
including a detailed task list with the responsible individuals, estimation
times, and completion dates (hardcopy).
Coding conventions
Writing code that compiles and runs is not enough. An important part of
software engineering is writing code that is also easy to read by other
programmers, not only those in your team but also those whom you've never met.
Since we will be reading each other's code, it is important for us to have
an agreed-upon set of conventions. Since the conventions themselves are
somewhat arbitrary, the following list has been compiled using some of the more
common approaches adopted in the industry.
- Spelling and syntax:
- class, struct, namespace, function, method: InterCaps style
(first letter of each word capitalized)
- typedef: same as class
- local variables, function parameters:
all_lowercase_with_underscore_between_words
- member variables of a class: same as local variables, but with
'm_' prefix
- macros, enums:
ALL_UPPERCASE_WITH_UNDERSCORES_BETWEEN_WORDS
- global variables (avoid these of course): same as local
variables, but with 'g_' prefix
- private methods: iInterCaps (intercaps but with a leading
underscore i)
- filename (if one file per class): ClassName.[h,cpp]
- braces { }: in the same column (C++-style), not opening brace at
end of line (Kernigan&Ritchie C-style)
- number of spaces in a tab: 2 (but insert spaces, not tabs!)
- Comments and parameter passing:
- Functions that do not modify the member variables of a class are
declared const
- Function parameters that are not modified (except native types) are
declared with const&
- Function parameters that are modified are declared with a pointer (*)
and come after all the inputs
- Functions local to a file are enclosed in an unnamed namespace to keep
its linkage internal to the file. Like private methods, these follow
the iInterCaps style.
- Just before each class declaration, a comment briefly describes the
purpose and functionality of the class, any non-obvious peculiarities, and
the author's name in
JavaDoc /
Doxygen format (starts with two asterisks, keywords start with @)
- Each header file starts with #ifndef #define, and ends with #endif;
double-underlines lead and trail name of file in ALL CAPS WITH UNDERSCORES
Example:
/**
This class keeps track of time.
@author Ima Coder
*/
class TimeManager
{
public:
typedef int SecondType;
TimeManager();
double GetTime(int day, const TimeStamp& another_time);
private:
double m_day_of_the_week;
};
Among the many standards on the web, Todd's very extensive and helpful
C++ coding
standard is similar to that above and also contains some insightful points
about software engineering in general. Wallach has a shorter
coding convention
list. Lott maintains an
extensive list of conventions, some of which are quite extensive :). Linus
Torvald's
conventions for the Linux kernel makes a fun read, though it's geared toward
C rather than C++. And, for something completely different, don't forget to
check out Microsoft's
Hungarian notation.
CVS (concurrent versions system) instructions
To start using CVS through WinCvs, either follow
Saurabh's
"Intro to WinCvs" or do the following:
First email your password to the grader so we can put it into the CVS passwd
file. (We will encrypt your password using
/usr/local/bin/perl -e 'print crypt("MyPassword","St") . "\n"; or using
/usr/bin/perl if that does not work. Feel free to encrypt the
password yourself if you'd prefer -- just be sure to let the grader know that it
has already been encrypted.) Note: CVS has poor security, so do not
use an important password for this project. Instead, send something that
you don't mind having compromised. Once you have done these steps, then
- Download and install WinCvs/MacCvs/gCvs
on your development machine
(Or, if you're working on a Clemson DCIT Windows machine and do not have
permission to install software, then copy the file
wincvs-postinstall.zip (the resulting install directory) to your U: drive
and unzip it)
- If you're not using Microsoft's Windiff, then download and install an
external diff program (e.g.,
WinMerge for Win32 or xxdiff
for Unix)
- Start WinCvs (wincvs.exe)
- Click Admin.Preferences
- Under General tab,
- Set CVSROOT to yourid@cvs.ces.clemson.edu:/pub/cvsprojects/ece417
(Replace yourid with your student id)
- Set Authentication to "passwd" file on the cvs server
- Under WinCvs tab,
- Enter path of external diff program, and click checkbox (For Windiff,
go to C:\Program Files\Microsoft Visual Studio\Common\Tools\windiff.exe)
- Set Home folder
- Click Admin.Login and type your password (this will store your password
locally in your Home folder/.cvspass)
- Click Create.Checkout module
- Enter module name {class/rootfly}
- Enter local folder to checkout to
- Now CVS is ready for you to add your own files, modify them, etc.! For
reference, see the on-line CVS
Cederqvist
manual or Redbean
manual
Alternatively, if you would prefer to just use the command-line version,
- Download and install the cvs client
on your development machine
- Create ~/.cvsrc file with a single line:
cvs -d :pserver:yourid@cvs.ced.clemson.edu:/pub/cvsprojects/ece417
(Replace yourid with your student id)
- type cvs login at the command prompt, along with your password
(this will store your password locally in your ~/.cvspass file)
- cd to the directory in which you want to copy files from the repository
- type cvs checkout name, where name is class/rootfly
- Now CVS is ready! For reference, see one of the manuals above
For the grader: To print a history of all checkouts and updates, cvs history -x UO -a
Individual assignments:
- HW#1 (due Friday, 1/21):
- Write a C++ class called File with the following public methods:
- empty constructor --- does nothing but initialize private members
appropriately
- constructor taking a const char* --- opens a file for reading using
the provided filename
- void Open(const char*) --- same as previous, but first closes the current
file if there is already one open
- void Close() --- closes the file if there is one open, otherwise does
nothing
- destructor --- same as previous
- bool ReadInteger(int*) --- reads the next integer in the file separated by whitespace;
returns a bool to indicate whether it was successful (0 indicates EOF, 1 indicates success)
Privately, the class should own a FILE* and access the file using C routines.
- Write a function int Add(const std::vector& a) that adds all the numbers in a
standard vector.
- Write a Visual C++ console-based application that takes a single command-line argument, namely,
the name of the file to open. When executed the program should open the file, read all the numbers
in the file until the end of the file is reached. The program should print all the integers one after
the other on stdout, after which it should print the total of all the
numbers, the total being computed by the Add function.
- To create a console app, follow these instructions: File -> New ->
Project -> Win32 Console Application. Give it a name (Name the workspace
userid_hw1, where userid is your Clemson user id) and keep the
checkbox on "Create new workspace". Choose "An application that supports MFC."
Now compile and run (Build -> Build ..., and Build -> Execute, or F7 and
Ctrl-F5). Under FileView -> Source Files you will find the main cpp file.
- Email the grader with the subject line "HW1" (without quotes). The
email should have the following files attached:
- username_hw1_exe (This is the precompiled executable, but with the
extension renamed so that it is not blocked by the email system).
- username_hw1_zip (This is a zipped version of your entire workspace
-- with extension removed -- with everything needed to compile your code.)
- all the source files that you actually wrote for the homework, attached as
individual text files (there will probably be only one or two of these).
- HW#2 (due Friday, 1/28):
- Write a struct called Line with four public member variables of type int:
x0, y0, x1, y1. Typedef Lines to std::vector<Line> .
- Write two
functions
- Save(const Lines& lines, const char* filename); -- saves the lines
to a text-based file. Each line of the file contains the four integers
x0, y0, x1, y1
- Load(const char* filename, Lines* lines); -- loads a text-based file into
a vector of lines.
- Write a Dialog-based application named Hw2 with the following appearance:
screenshot1.bmp . The behavior should be
as follows:
- Clicking on "Load..." should cause a file open dialog box to appear;
when the user selects a file, that file is loaded, and the resulting lines
stored in a member variable m_lines of the CHw2Dlg class. The contents of
the file should be displayed in the read-only edit box, and the lines should
be drawn on the window.
-
Clicking on "Save As..." should cause a file save as dialog box to appear;
when the user selects a filename, then m_lines is stored in the file.
-
Clicking on "Add Line" should put the application into a mode in which the
next two mouse clicks by the user on the window define a new line that is
then added to m_lines. When the line is added, it is also drawn on the
screen and displayed in the edit box.
-
Clicking "OK" or "Cancel" causes the application to exit.
-
Some helpful tips:
- To create a Dialog-based application in VC++, File => New => Projects => MFC AppWizard (exe) => Enter name of project and set the location
(directory) => Dialog based => uncheck ActiveX Controls => Next => Finish.
- To add a pushbutton or an edit box, go to Resource View => Dialog =>
IDD_HW2_DIALOG, and drag an item from the floating Controls panel.
- To change the name displayed on a button, right-click on the button =>
Properties => General => Caption.
- To make the edit-box read-only and multiline, right-click on the edit
box => Properties => Styles => multiline and read-only
- To add a callback to a button, click on the button, then View =>
ClassWizard => MessageMaps => BN_CLICKED => Add Function => OK => Edit Code.
This will create the callback and take you there. To go back to the
graphic editor, use Ctrl+Tab or Window => Hw2.rc - IDD_HW2_DIALOG (dialog).
- To add m_lines to the dialog, manually insert it into the class
declaration in Hw2Dlg.h as a private member variable.
- To create a file open dialog box, use CFileDialog fdlg(TRUE); to
create a file save as dialog box, use CFileDialog fdlg(FALSE); To
display either dialog, use the DoModal() method with no parameters.
The return value will indicate whether the user clicked ok, and the
GetPathName() method will return the filename. For more help on the
CFileDialog class, see the
MSDN help on CFileDialog . (You can also get to this -- or any
other MFC -- help page quickly by searching in google for the name of the
class.) Click on "Class Members" to get information about the methods
of the class.
- To get help on the CString class, see the
MSDN help on CString . In particular, notice that concatenation is
performed by the + operator, and that the Format(...) method creates the
string from a format string as in printf(). The CString class is
really handy, especially for building the text to display in the edit box.
- To display a string in the edit box, first create a member variable of
the class corresponding to the edit box. This can be done by clicking
on the edit box => View => ClassWizard => Member Variables => Add Variable
=> type a name, such as m_edit1 => change Category to Control => OK.
Now the CHw2Dlg class has a member variable named m_edit1 that corresponds
to the edit box. To display a string in the edit box, call the
SetWindowText() method of the edit box class, passing a CString as the input
parameter. Be sure to use "\r\n" as the newline character.
- To add a callback for a left button press, View => ClassWizard =>
Message Maps => Hw2Dlg under Object IDs => WM_LBUTTONDOWN under Messages: =>
Add Function => Edit Code
- To draw all the lines in m_lines, create a CPaintDC in the OnPaint
method of the dialog class. IsIconic is used when the window is
minimized, so we do not want that. Instead, in the else clause, just
before CDialog::OnPaint(), add the following line of code: CPaintDC
dc(this). CPaintDC is derived from CDC, which contains all the interesting
functions. To draw a red line, use the following code:
CPen pen(PS_SOLID, 1, RGB(255,0,0));
CPen* oldpen = dc.SelectObject(&pen);
dc.MoveTo(x1, y1);
dc.LineTo(x2, y2);
dc.SelectObject(oldpen);
- Do not call OnPaint() directly. Rather, to force the window to be
redrawn, call Invalidate() from within any method of the dialog class.
For example,
MyDlg::OnButton1()
{
Invalidate(); // causes OnPaint() to be called
}
- Be sure to write readable code, and to follow the coding
conventions on the website (above).
- Email the grader with the subject line "HW2" (without quotes). The
email should have the following files attached:
- username_hw2_exe (This is the precompiled executable, but with the
extension renamed so that it is not blocked by the email system).
- username_hw2_zip (This is a zipped version of your entire workspace
-- with extension removed -- with everything needed to compile your code.)
- all the source files that you actually wrote or modified for the homework, attached as
individual text files (there will probably be only a small number of these).
Group assignments:
- Milestone#1 (due Monday, 2/7, by 11:59pm):
- Write a Dialog-based application named Rootfly with the following appearance:
screenshot2.bmp . The behavior should be
as follows:
- File => Load Images... allows the user to select one or more BMP image
files, whose names are stored in a standard vector of CStrings called
m_filenames that is a member of the dialog:
- File => Open... allows the
user to open the root ASCII file saved by "Save As...". The data
loaded clobbers all the data currently in the system and displays the first
image with any roots overlayed.
- File => Save As... allows the user to
save the current roots to an ASCII file with the format specified below.
-
File => Exit closes the application
- Previous and Next buttons cycle
through the images loaded. If the user is at the beginning or end of
the sequence, then the buttons do nothing.
- The read-only edit box next to
the "Next" button displays the current image number (zero-indexed) and the
total number of images.
- The "New Root" button allows the user to click
twice in the image to define a new line segment, which is then displayed as
a red line. These roots are saved in the file when the user
selects "Save As..."
- When the user selects a new image (using Previous or
Next buttons), the image is displayed, with all the roots for that image
overlayed.
- Check the code into the CVS repository under the groupXX folder, where
XX is replaced by your group number. There should be one project per
group. Check in all the files needed to compile your code. Add
the .ico file as binary. Do not check in the .opt, .plg, .aps, .clw,
or .ncb files, and do not check in the Debug or Release directories.
- When you have checked in your code, it is recommended that you check it
out again and compile to be sure that you checked in all the necessary
files. We will check out your code sometime after midnight and verify
that it works.
- When you are done, email the grader with a single file per group
specifying the percentage of effort done by each group member. If all
of you cannot agree, then note that as well. The percentages are a
safety measure just in case a group member is not pulling his or her weight.
- Auxiliary files:
- The code to load and display images is here:
Image.h, Image.cpp,
BmpFile.h, BmpFile.cpp. To add the files
to your project, in FileView right-click on Rootfly files => Add files.
- If you cannot recall your group number, the list is here:
groups-417617.xls or
groups-417617.txt
- ASCII File format:
number-of-images
filename number-of-roots-in-this-file (the filename may be relative or
absolute)
x0 y0 x1 y1 (coordinates of ith root for this file, one line for each root)
... (continued for all roots in this file)
... (continued for all images)
[Here is a sample file with three images, 2
roots for the 1st image, 0 roots for the 2nd, and 1 root for the 3rd]
- Some sample image files: image001.bmp,
image002.bmp, image003.bmp
- Some helpful tips:
- It is recommended that you turn on precompiled headers for all projects
you create in Visual C++. To do that, Project => Settings => click on
project name (Rootfly) => change Win32 Debug to All configurations => C/C++
tab => change General to Precompiled headers => Not using precompiled
headers
- To create a menu for a dialog class,
- in ResourceView, right-click on Rootfly resources => Insert => Menu =>
New
- right-click on the new IDR_MENU1 and rename it to IDR_MENU_MAIN
- close Rootfly.rc (or just close all windows)
- Open Rootfly.rc in text mode (File => Open => Rootfly.rc (Open As Text))
- Just under the line
EXSTYLE WS_EX_APPWINDOW
insert the line
MENU IDR_MENU_MAIN
(This tells the dialog class that it has a menu, and that its menu is
IDR_MENU_MAIN.)
- Save Rootfly.rc and close it.
- In ResourceView, open Rootfly resources => Menu => IDR_MENU_MAIN
- Click on the top-left of the empty menu and type "&File" (without the
quotes). The ampersand makes the letter 'F' the keyboard shortcut
- Click on File and select the empty box just below it. Type
"&Open". Just under it, type "E&xit".
- Compile and run. You will see the menu at the top of the dialog.
- To add the callbacks to the menu items,
- In ResourceView, open the menu and click on the "&Open" box.
- View => ClassWizard => OK (select an existing class) => CRootflyDlg =>
Select => Command => Add function => OK => Edit code
- To exit the application, call PostMessage(WM_CLOSE) in
CRootflyDlg::OnFileExit()
- To create a group box, click the group box icon in the Controls panel.
Change the displayed text to "Image", and change the ID to ID_STATIC_IMAGE
(If you don't change the name then you won't have access to it.) Use
the ClassWizard to add a member variable called m_static_image.
- To get the client rect of the group box, call
CRect rect;
m_static_image.GetWindowRect(&rect);
ScreenToClient(&rect);
- To create a file dialog that allows the user to select multiple files,
use
CFileDialog dlg(TRUE, NULL, NULL, OFN_ALLOWMULTISELECT);
Then, to get the filenames, use the GetStartPosition() and GetNextPathName()
methods of CFileDialog.
- All the image commands are in a namespace called blepo. To load an
image from a file, call
#include "Image.h"
blepo::ImgBgr img;
blepo::Load("file.bmp", &img);
- To draw an image on the screen, call
CPaintDC dc(this);
CRect src_rect(0, 0, img.Width(), img.Height());
CRect dst_rect; // initialize this to your window area
blepo::Draw(img, dc, src_rect, dst_rect);
- To read a string from a file, call
const char str[100];
fscanf("%s", str);
- Milestone#2 (due Friday, 2/18, by noon):
- Extend your Rootfly application in the following ways:
- File menu should have just the following commands:
- New closes the existing document (if there is one) and resets the
screen
- Open... displays a file dialog box that allows the user to open just
a single Rootfly file (*.rfy).
- Save saves all the current data to the current filename
- Save As... displays a file dialog box so the user can save the file
- Exit closes the program, prompting the user to save if changes have been
made
- Main window should have the image displayed, a "New Root" button, and ways
for the user to change the tube, transect, window, and session. Here is
a suggested screenshot: screenshot3.bmp .
When the user opens the .rfy file, the program should scan the directory
containing the file to find all corresponding image files, storing a list of
all the filenames, and setting the ranges of all the spin button controls.
(You will not be penalized for implementing the code in this outdated way, but it is no longer necessary.
The newer way that we discussed in class, described next, should be significantly simpler.)
- When the user opens the .rfy file, the program should set the ranges of all the spin button controls, and it should
search the directory for the first image file.
- The image files will have the following name:
exp_SS_UUT_FF exp_UUT_WW_SS, where
SS is a 2-digit number indicating the session; UU is a 2-digit number
indicating the tube; T is the letter A, B, or C indicating the transect; and
WW is a 2-digit number indicating the window. Example code to write the
filename:
int tube, frame, session;
char transect;
sprintf("exp_%02d%c_%02d_%02d", tube, transect,
window,
session);
You do not need to handle gaps in the numbers. E.g., if sessions 1,
2, 4, and 5 exist, you may safely ignore 4 and 5. (no longer necessary)
- When the user types in the edit boxes or uses the spin button controls,
the correct image is displayed. If out of range, the closest image is
displayed.
- Clicking New Root puts the application into a mode in which the user can
click on the image multiple times; a double-click indicates the last point in
the root. After the double-click, the root should be displayed as a red
line. The user can repeat this process, adding multiple roots per image.
- The recommended data structures were given in class.
- The suggested Rootfly file format is as follows:
- first line: ROOTFLY_TMP1
- second line: exp_%2U%1T_%2W_%2S
- third line: <number of tubes> <number of transects> <number of
windows> <number of sessions>
- zero or more tube-blocks, where tube-block contains
- tube <tube number><transect letter>:
- <root-blocks> (num-windows * num-sessions of them, with session as the
inner loop), where a root-block contains
- number of root lines
- zero or more root-lines, where root-line contains
- <number of points> <point-list> <diameter> <color>
- where
- point-list is x0 y0 x1 y1 x2 y2 etc.
- diameter is a floating point number
- color is a single-word lowercase string, one of
- darkbrown
- lightbrown
- white
- black
- Example suggested Rootfly file: sample-rootfly.rfy
. In this file, there is 1 tube, 1 transect, 2 windows, and 2 sessions.
The 2nd window, 1st session contains 2 roots. All other windows and
sessions contain no roots.
- Suggestions:
- To create a spin control, click on the Spin button in the control panel
- To make the spin control a buddy of the edit box, right-click on spin
control and select "Auto buddy" and "Set buddy integer"
- (For autobuddy to work, the spin control needs to be just after the edit
box in the tab order. The easiest way to do this is to create the edit
box, then create the spin control. If the widgets get out of order, you
can always change the tab order using Layout->Tab order.
- Right-click on spin control and select Alignment->Right to visually join
the two controls.
- Create a member variable associated with the spin control in the same way
as we did before. It will be of type CSpinButtonCtrl.
- To set the spin range, use the function SetRange32, as in
m_spin_tube.SetRange32(0, 100); (Note: By default, the range is
backwards, which makes the buttons work backwards.)
- To find all files in a directory, use CFileFind and its methods FindFile,
FindNextFile, IsDots, and IsDirectory.
- Check in your code to CVS to turn it in, and email the grader with percent
effort for each group member.
- Note: We are following an open-source model, so you may check out or
update all the group folders for the previous milestone (but no later than
11:59pm 2/12)
- Milestone#3 (due Friday, 3/4, by noon):
- If your group number is odd,
- Change the application to maintain the individual roots over time (the
correspondence problem).
- Change the Rootfly file format.
- Here is one suggestion: (sample file:
sample-rootfly-3.rfy)
- first line: ROOTFLY_TMP3
- second line: exp_%2U%1T_%2W_%2S
- third line: <number of tubes> <number of transects> <number of
windows> <number of sessions>
- zero or more lines, where line contains one of the following:
- g: <tube> <transect> <window> <session> x-offset y-offset
- (x-offset, y-offset) is the global offset of the coordinates in session
with respect to the first session
- r: <tube> <transect> <window> <session> <root-number>
<number-of-points> <point-list> <diameter-center> <diameter> <color>
- Here the points are with respect to the session's coordinate system, which
is shifted with respect to the first session by the global offset
- number-of-points is 0 indicates that the root died in this session
- Here is another suggestion: (sample file:
sample-rootfly-2.rfy)
- first line: ROOTFLY_TMP2
- second line: exp_%2U%1T_%2W_%2S
- third line: <number of tubes> <number of transects> <number of
windows>
- zero or more tube-blocks, where tube-block contains
- tube <tube number><transect letter>:
- <window-blocks> (num-windows of them), where a window-block contains
- global offset line, which contains
- <num-sessions> gx0 gy0 gx1 gy1 etc. (num-sessions of the global offsets)
- number of root-blocks
- zero or more root-blocks, where a root-block contains
- <first-frame> <number-of-frames> <live or dead>
- root-lines (number-of-frames of them), where root-line contains
- <number of points> <point-list> <diameter> <color>
- where
- point-list is x0 y0 x1 y1 x2 y2 etc.
- diameter is xc yc diam, where
- (xc,yc) are the coordinates where the diameter is drawn on the image
- diam is a a floating point number indicating the diameter
- color is a single-word lowercase string, one of
- darkbrown
- lightbrown
- white
- black
- Change the Rootfly data structures as mentioned in class.
- Display the one-based root number next to the root drawn on the image.
Hint: Use CDC::TextOut function.
- After the user double-clicks to indicate the end of a new root being
added, the next two mouse clicks should be used to indicate the diameter.
Draw a circle defined by the two clicks. The interior color of the
circle should be filled with black, white, light brown, or dark brown.
(The color can be any of these for now. The user does not have to be
able to specify color for this milestone.)
- Allow the user to register two images from adjacent sessions. When a
new session is displayed, the live roots from the previous session are copied
over. The user can press the Register button, then the next mouse click
and drag moves all the roots. Actually it doesn't change the root point
lists directly, but it sets a global (x,y) offset with respect to the first
session, and this offset causes the root display to change.
- If your group number is even,
- Design a dialog box that pops up when File->New is selected. The
dialog box should enable the user to indicate the filename format, the
directory, and the name of the Rootfly file.
- Design a dialog box that pops up when Tools->Process Video is selected.
The dialog box should allow the user to select multiple image files from a
FileOpen dialog box. Then the user should be able to sequence through
these files, as if playing a video (with Previous and Next buttons).
When the user presses Save, the image is saved to a file with a filename
specified according to a file format that the user can change (as in
File->New). After saving the file the filename is updated automatically
according to rules specified on the UI.
- Tip: To create a dialog box, ResourceView -> Rootfly resources ->
right-click on Dialog -> Insert Dialog. Then right-click -> Properties
-> Change the name of the dialog. Then Ctrl+W -> Create a new class.
Let the new class handle the callbacks. In your code, call
CProcessVideoDialog dlg(IDD_PROCESS_VIDEO_DIALOG);
dlg.DoModal();
(or whatever name you choose)
- Combine code from odd and even groups to produce a single working
application. For example, groups 1 and 2 pair together, groups 3 and 4,
etc. The final working application should be in the odd group's CVS
directory.
- Sample images can be found in the class/rootfly/data directory.
- According to our open-source model, feel free to check out or
update all the group folders for the previous milestone (but no later than
11:59pm 2/22)
- Milestone#4 (due Friday, 3/18, by noon):
- Building upon the existing functionality from previous milestones, the
tasks for this milestone are as follows:
- odd groups:
- select a root by clicking on or near the points, line segments, circle, or
number
- display properties of selected root (id, diameter editbox, color drop-down
box, dead or alive drop-down box)
- editing location of root points (Click and drag an individual point to a
new location; suggestion: use a checkbox with a push-like style to
indicate editing mode)
- editing diameter and color (Click and drag circle, or change diameter in
text box; change color using drop-down box)
- display whether file modified (using asterisk * in title bar); prompt user
before New, Open, or Exit whether to save changes (Yes, No, or Cancel)
- display root color inside circle (white, black, dark brown, or light brown
-- make sure colors are easily distinguishable)
- navigate to arbitrary session, etc., by typing number in edit box and
hitting return
To do this, override the CRootflyDialog::OnOK() method. For example,
suppose you have an edit box associated with the variable m_edit1 (of type
CEdit). Then, in OnOK, check whether the edit box has the focus, and, if
so, just return from the function without calling the base class' CDialog::OnOK:
void CRootflyDlg::OnOK()
{
if (GetFocus() == &m_edit1)
{
// move to
the new location, based upon the value in the edit box
return;
}
CDialog::OnOK();
}
- copy the roots from one session to another using a "Copy Previous Session"
button
- even groups:
- display "no image" if no image available but within range
- play/pause, fast forward (2x), and rewind (2x) buttons for processvideo
dialog
- scan image directory to determine dimensions of tube, transect, window,
and session. Do the scan automatically whenever the user does New, Open,
or closes the processvideo dialog. The new dimensions should be the max
of the old dimensions and those found by scanning the directory (i.e., do not
shrink the dimensions just because some images are not found).
- display 5 images along bottom (different sessions), and 5 along the left
(different windows). Draw a rectangle around the middle one in both cases (use
CDC::FrameRect).
- File => New should now prompt the user to enter the directory for the
file, and nothing else. Use CFolderDialog from
http://www.codeproject.com/dialog/cfolderdialog.asp or group03.
- Move the image filename format dialog box to the Tools => Options dialog.
Make sure that it is powerful enough to handle (at least) the following
formats:
- Name_UUA_WW_SS (our format)
- Name_TubeUUA_SS_WW (Eric's format)
- Name_SS_UUA_WW (Cory's format)
- Name_UUA_SS_WW (Dr. Wells' format)
where UU is the tube, A is the transect (single character), WW is the window, and SS is the session.
- Save the image filename format to the Rootfly file. When the user
loads a Rootfly file, the program should use the format in the file, not the
default format.
- For the demo, check in a single rootfly file named exp_group01.rfy (or
whatever odd group you belong to) in the rootfly/data/root_collection
directory. We will open these files, as well as start from scratch using
File->New. We will also import images from the data/root_movie directory
using the processvideo dialog.
- According to our open-source model, feel free to check out or update all
the group folders for the previous milestone (but no later than 11:59pm 3/7)
- Milestone#5 (due Monday, 4/4, by noon):
- For this milestone, be sure to have all the functionality of the previous
milestone implemented and working, with appropriate safety checks in place
(e.g., the application should not crash).
- The new groups are:
groups-417617.xls or
groups-417617.txt
- Milestone#6 (due Friday, 4/15, by noon):
- For this milestone, add the following functionality:
- odd groups:
- extend root endpoints
- delete root entirely
- show root IDs check box
- show dead roots => affects all sessions
- while drawing new root,
- draw line while mouse is moving
- draw circle automatically after final doubleclick; single click sets
diameter of circle, while circle center is the last point of the root
- copy root data from one session to another
- even groups:
- full screen (approx. 1024 x 768) for main dialog; process video dialog
should be approximately 3/4 of full size; display the image as 640 x 480, no
matter what the input image size is
- slider for process video dialog (see hints below)
- export to .csv file (see the sample
spreadsheet output)
- conversion to millimeters (edit box to set the conversion factor
pixels/millimeters; factor should be a floating-point number; factor should be
saved to the .rfy file; pixels should be with respect to the original image;
length and diameter displayed on the screen, as well as data in the .csv file,
should all be in millimeters)
- sort movie files alphabetically, no matter what order they are returned by
the file open dialog
- Technical hints on slider:
- Use
CSliderCtrl . GetPos, SetPos, SetRange, etc., are pretty
straightforward.
- The main callback is called OnHScroll, and it does not come to the
CSliderCtrl but rather to the dialog containing the slider. Therefore,
use the ClassWizard to create an OnHScroll callback to the process video
dialog. Here is some sample code illustrating how to use this callback:
void CProcessVideoDialog::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar*
pScrollBar)
{
int minpos, maxpos;
CSliderCtrl* slider = (CSliderCtrl*) pScrollBar;
assert(GetDescendantWindow(IDC_SLIDER1) == slider);
slider->GetRange(minpos, maxpos);
// Set the new position of the thumb (scroll box).
unsigned curpos = nPos;
// Determine the new position of scroll box.
switch (nSBCode) {
case SB_LEFT: curpos = minpos; break;
// Scroll to far left
case SB_RIGHT: curpos = maxpos;
break; // Scroll to far right
case SB_ENDSCROLL: return; // End
scroll -- just ignore
case SB_LINELEFT:
case SB_PAGELEFT:
case SB_LINERIGHT:
case SB_PAGERIGHT:
curpos = (unsigned) slider->GetPos();
break;
// case SB_THUMBPOSITION:
// case SB_THUMBTRACK:
}
// slider->SetPos(curpos); // is this necessary?
CDialog::OnHScroll(nSBCode, nPos, pScrollBar);
}
- Milestone#7
- You have until midnight Saturday to checkout code from other groups and
get your app working again. Testing may begin at any time, but it is
recommended that you wait until Monday to make sure that the app is working.
- Part A -- testing and bug finding (due Friday, 4/22, by noon):
- For this part, even and odd groups work together; there is no distinction
between them
- Each group is responsible for testing the group whose number is just above
it, modulo the number of groups. Thus, 1/2 tests 3/4, 3/4 tests 5/6, 5/6
tests 7/8, 7/8 tests 9/10, and 9/10 tests 1/2.
- The six members of a supergroup should divide the testing between them.
Each member of the supergroup should do roughly an equal amount of testing.
To make this job easier in the case that someone wants to get started before
you are able to call a big supergroup meeting, my recommendation would be for
that person to email the supergroup letting them know which tests they plan to
run. This should prevent conflicts.
- Collectively as a supergroup, thoroughly test the other group's code.
The list of tests to be performed are contained in testlist.xls, which is an
Excel file that is checked into the root_collection directory. Each
supergroup has one testlist.xls file (e.g., testlist_group01.xls contains the
tests for group01's executable -- BE CAREFUL: DO NOT USE THE FILE
CORRESPONDING TO YOUR GROUP, BUT RATHER TO THE GROUP WHOSE EXECUTABLE YOU ARE
TESTING). When you perform a test, indicate whether it succeeded or
failed, along with any comments you have (particularly if it failed), and your
name or userid (to identify you as the tester). Ignore the last two
columns, which will be used by the group fixing the bug.
- In addition to running the tests, each person is responsible for finding
one additional "bug" in the code. The bug can be at any level of
severity, from feature request to suggestion to crashing. The bug should
be added as a line at the end of the testlist.xls file.
- Part B -- bug fixing (due Friday, 4/29, by noon):
- All the bugs indicated in the testlist.xls file from regular testing, as
well as any additional "bugs" that are critical (e.g., crashing), should be
fixed. When you fix a bug, indicate that you have done so using the last
two columns of the testlist.csv file (the last column is for your name or
userid).
- Feel free to start early, no need to wait until all bugs come in.
- Put the GNU GPL at the top of each of your .h and .cpp files:
/*
* Rootfly: A program for analyzing and measuring roots.
* Copyright (c) 2005 Clemson University.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
- Write a short document explaining your file format, data structures, code
organization, and anything else that might help a future developer to use and
extend your program.
Instructor: Stan Birchfield, 207-A Riggs Hall, 656-5912, email: stb at clemson
Grader: Nikhil Rane, nrane at clemson
Lectures: 2:30 - 3:20 MWF, 227 Riggs Hall