ANALYSIS OF BODY MOVEMENT AND ITS EFFECTS ON

CYBERWARE 3D WHOLE BODY SCANNER

A Thesis Presented to

The Faculty of the

Fritz J. and Dolores H.

Russ College of Engineering and Technology

Ohio University

In Partial Fulfillment

of the Requirement for the Degree

Master of Science

By

Anmin Hu

August, 1999

OHIO UNIVERSITY ACKNOWLEDGEMENTS

I, Anmin Hu, would like to take this opportunity to thank several people who make thesis become possible.

First, I would like to express my deep appreciation and thanks to my advisor,

Dr. Joseph H. Nurre, for his directions. He has been so kind and patient to help me when I had problems. "Thanks a lot! Dr. Nurre".

I would like to thank my friend, Collier Jeff and Lewark Eric, who are the graduate students of Dr. Nurre. They always gave me hints and help when I had the troubles. This helps me a lot.

I would like to thank Mr. Brian Comer, who is research scientist in US Army

Natick RD&E Center, to provide the 3D scan data. Without his assistance, this thesis can not be formed.

I also would like to thank Dr. Jeffrey Giesey, Dr. Mehmet Celenk to be the members of the thesis committee and Dr. Bhavin Mehta to be the college representative of the thesis committee. Thanks for your time to revise my thesis. Contents

Chapter One Introduction 1

Chapter Two Literature Review 5

Chapter Three Body Sway Analysis in Cyberware WB4 Scanning 10

3.0 Introduction 10

3.1 Analysis Method 10

3.1.0 The Cyberware Whole Body Scanner 10

3.1.1 Scan the Subject with the Cylinder Attached 12

3.1.2 Post-Processing of 3D Cylinder Surface Data 14

3.2 Software Implementation 18

3.2.0 Data Sort by Z Cordinate 18

3.2.1 Implementing Furthest Point Analysis Algorithm 18

3.3 Verification of the Analysis Method and its Implementation 19

Chapter Four Simulation and Analysis of Body Sway Using Jack Package 27

4.0 Introduction 27

4.1 Develop the Human Body Model Using Jack 27

4.1.0 Peabody Object Representation 27

4.1.1 Develop a Model Based on Peabody Language 28

4.2 Software Simulation of Body Movement Using the Model 28

4.2.0 Introduction 28

4.2.1 Lisp Interface and JCL 28

4.2.2 C&C++ API 29 11 4.2.3 Network Jack 30

4.2.4 Software Simulation Methods 31

4.3 Software Implementation of 'jackmove' 33

4.3.0 Introduction 33

4.3.1 Establish RPC connection between Jack Program and

'jackmove' Program 33

4.3.2 Specify the Movement of the Center of Gravity 34

4.3.3 Adjust Joint 35

4.3.4 Initialize Node Position and Apparel Length 36

4.3.5 Analyze the Body Movement 38

4.3.6 Analyze the Apparel Measurement Error 39

4.3.7 User Interface 39

Chapter Five Results 43

Chapter Six Conclusion and Future Research 52

Bibliography 54

Appendix l.x C Programs for Chapter Three 56

Appendix 1.0 measure.h 56

Appendix 1.1 measure.c 57

Appendix 1.2 plyLoad.c 58

Appendix 1.3 dataSortByZ.c 61

Appendix 1.4 dataStatistic.c 63

Appendix 1.5 cutoff.c 65

Appendix 1.6 dataAnalysis.c 66 iii Appendix 1.7 calculate.c 67

Appendix 2.x C Programs for Chapter Four 70

Appendix 2.0 capi.h 70

Appendix 2.1 main.c 71

Appendix 2.2 move_center_gravity.c 72

Appendix 2.3 adjustJoint.c 73

Appendix 2.4 datalnit.c 78

Appendix 2.5 initial_Iength.c 79

Appendix 2.6 picknewpoint.c 80

Appendix 2.7 showmovement.c 81

Appendix 2.8 showlengtherror.c 82

Appendix 2.9 shownode.c 84

Appendix 2.10 mainmenu.c 85

Appendix 2.11 jointmenu.c 86

Appendix 2.12 nodemenu.c 87 iv Figures

Figure 3.1 The Cyberware Whole Body Scanner 11

Figure 3.2 The Researcher uses Cyberware WB4 scanner to collect the

Human body anthropometric data in a simple pose 12

Figure 3.3 Subject with Cylinder Attached to His Front Torso Showing

Scanning Position 13

Figure 3.4 Cylinder extracted from whole body scan 13

Figure 3.5 An Actual Z-slice of the Cylinder in 2D 14

Figure 3.6 A Diagram to Show How to Implement 'Furthest Point Algorithm' 16

Figure 3.7 A Linked-list to Store the Furthest Point for all Z-slices 19

Figure 3.8 A Static Cylinder is Scanned 20

Figure 3.9 A Moving Cylinder is Scanned 20

Figure 3.10 The Graph for Static Cylinder Scan 22

Figure 3.11 The Graph for Moving Cylinder Scan 23

Figure 3.12 The Graph for Moving Cylinder Scan 24

Figure 3.13 The Graph Showing the Subject's Intentional Sway 25

Figure 3.14 The Graph Showing the Subject's Intentional Sway 26

Figure 4.1 Jack Model 29

Figure 4.2 Network Jack and its Implementation 31

Figure 4.3 User Interface I 40

Figure 4.4 User Interface II 41

Figure 4.5 User Interface III 42

Figure 5.1 First Scan of the Subject Fitted with Cylinder 44 v Figure 5.2 Second Scan of the Subject Fitted with Cylinder 45

Figure 5.3 Third Scan of the Subject Fitted with Cylinder 46

Figure 5.4 Fourth Scan of the Subject Fitted with Cylinder 47

Figure 5.5 Fifth Scan of the Subject Fitted with Cylinder 48 vi Tables

Table 1. Body Sway From the Five Scans 50

Table 2. Anthropometric Measurement Errors From the Five Scans 50 CHAPTER ONE

INTRODUCTION

Variations in human body size are tremendous. Both military and civilian industry frequently use anthropometric data to access the range of body size within their target populations. These comparative measurements guide the design and sizing of uniforms and other apparel. Engineers also use these data to optimize the layout of vehicles and workstations with respect to key parameters, such as reach, clearance, egress, and ingress.

So, where does the anthropometric data come from?

Traditional methods are based on measurements, such as segment lengths, breadths, and circumferences. These measurements were obtained with standard tools including anthropometers, calipers, and tape measures. However, within the past ten years, the state-of-the-art in anthropometric data collection has moved away from these tools toward non-contact 3D scanning. This trend began with scanning systems in the mid-1980s for the head, face, and other body segments and has recently evolved into whole-body scanning.

Two primary technologies of the whole-body scanning system have emerged in the United States as valuable candidates for surface digitizing and measurement of the human body. Both are optically based and non-contact. The laser-based scanning system was developed and marketed by Cyberware Inc. in Monterey, California. A moire-based light-projection system was developed for commercialization by Textile and Clothing

Technology Corporation in Cary, North Carolina. 2 The whole body scanning system, built by Cyberware, employs a laser-scanning

triangulation method to acquire 3D images. In this design, a stripe of light is emitted from four laser diodes onto the scanning surface, then viewed simultaneously from two locations using an arrangement of mirrors. Viewed from an angle, the laser stripe appears deformed by the object's shape. These deformations are recorded by a CCD sensor and digitized. The cameras positioned with each of four scanning heads record this surface information as the scan heads traverse the length of the scanning volume from top to bottom. The separate data files from each scanning head are then combined in software to yield a complete integrated image of the scanned object.

The Cyberware whole-body scanning system can image a person's surface and provide data for further post-processing. The scanned volume is approximately equal to a

2-meter high by 1.2-meter diameter cylinder. These dimensions accommodate the vast majority of human subjects. The spatial resolution of image ranges 5 millimeters in the x­ axis, 2 millimeters in the y-axis, and 2 millimeters along the z-axis. Scanning speed for the maximum scanned volume is around 17 seconds, which yields about 400,000 3D coordinates on the surface of an adult human body.

The first two commercial whole-body scanning systems built by Cyberware have been delivered to both the U.S. Army Natick RD&E Center and the U.S. Air Force's

Computerized Anthropometric Research and Design Laboratory. Researchers in the

Computerized Anthropometric Research and Design Laboratory used the Cyberware scanner principally for aircrew-helmet and oxygen mask design, as well as for medical applications for bum victims and amputees. The Human Engineering Division of

Armstrong Laboratory at Wright-Patterson introduced the Cyberware whole-body scanner 3 to improve the fit of commercial and military clothing, while bettering the design of

aircraft cockpits and crew stations. Of course, civilian applications for the Cyberware

whole body scanner could be as valuable as those for military applications. For example,

the apparel industry is intensely interested in scanning people for potentially more

affordable, custom-tailored clothes.

Although the laser-based 3D whole body scanning system has been put into

commercial applications, some hurdles still confront the mainstream use of this promising technology. Some problems are fundamental - data accuracy and reliability, for example - and will affect all potential applications. This thesis will focus on the basic research conducted on 3D data digitizing accuracy and reliability. The Cyberware whole body scanner images the human body for about 17 seconds as the cameras travel from head to toe. This process yields thousands of digitized profiles from each of the scanning heads. The whole-body image is integrated from these digitized profile data during post- processing. With a scanning time of about 17 seconds, the effects of body movement on scan quality and overall data accuracy are potentially quite significant - even shallow breathing can affect the integrity of the 3D image.

In this thesis, the 3D digitizing errors introduced by subject movement during the approximate 17 seconds scanning time are investigated. Further, the anthropometric measurement errors from the above digitizing errors are analyzed. The research methods used in this thesis are original and direct. The contributions of this thesis will further promote the potential applications of the whole-body scanning technology.

The structure of this thesis is as the follows: Chapter One introduces some basic concepts of the laser-based Cyberware whole-body scanner and the task of the thesis. 4 Chapter Two will discuss previous research in the field and will also give a brief background discussion of the thesis. Chapter Three presents the method and its software implementation for analyzing body movement during the whole-body scanning. Chapter

Four presents a software simulation and analysis of body sway based on the Transom

Jack Package used for analyzing centre gravity movement and its effects on the apparel measurement errors. Chapter Five presents the results. Finally, in Chapter Six, some conclusions and recommendations for future research are given. 5 CHAPTER TWO

LITERATURE REVIEW

Since the introduction of a commercial laser-based Cyberware whole body

scanner, scientists, engineers, and others have sought to exploit the potential of this

exciting technology. To acquire a full body scan, a human subject needs to maintain an

upright posture for a finite period of time. Normal upright standing is not, however, a

static posture. The body of an apparently motionless, standing man undergoes continuous

micro-movements of which he is unaware. These body movements by the subject will

cause discontinuities in the 3D data and can invalidate the measurements. So, a more

detailed investigation of body movement will be required while using the whole body

scanner. In this chapter, previous research on postural stability of a standing subject is

reviewed. Most of them are based on the common interests of body sway.

The characteristically erect standing posture of man has attracted systematic study for well over a century. Normal standing is not a static posture. The body is in continuous motion, even when an attempt is made to stand quite still. This was first established experimentally by Vierordt [1]. From the motor control of the nervous system, Vlandimir [2] presented that the upright posture of man is maintained by a complex reflex process that ensures the maintenance of body equilibrium. It is controlled by the uninterrupted flow of impulses reaching the central nervous system from muscle and tendon proprioceptors, skin exteroceptors, and the vestibular and visual apparatus. A continuous sequence of random disturbances tends to upset the equilibrium of the body. Impulses originating in these receptors activate reflex 6 contractions in the muscular fibers, which counteract these disturbances and restore the equilibrium. Thus, reflex contractions in the musculature cause continuous body oscillations that maintain the dynamic equilibrium of the upright posture.

Recently, numerous methods have been devised and developed in an attempt to quantify and analyze postural sway in humans. The most common methods have dealt with the variation of the centre of pressure of the vertical footground reaction forces.

D. P. Thomas and R. J. Whitney[3] used a force analysis platform to obtain a continuous record of the horizontal forces of reaction at the feet and co-ordinates of the centre of foot pressure for a subject standing normally on the platform. The platform on which the subject stands is one meter square and elastically suspended about 25 ern above the ground, and its horizontal movement is elastically restrained.

The platform has strain gauges attached to three or four comers, and the forces measured are combined to produce the position of the centre of force in the horizontal plane. An accelerometer mounted on the trunk was used to obtain a simultaneous record of the movements of the upper parts of the body. From their investigations, all forms of postural sway activity were cyclical in nature and included high- and low­ frequency components. In the case of forces of reaction at the feet, effective separation of high-frequency from low-frequency bands was possible. The low-frequency components of movements of the centre of foot pressure were always very irregular.

The average amplitude of the low-frequency movements of the center of the foot pressure varied between subjects from 0.36 em to 1.13 em. The high-frequency movements showed greater regularity than the corresponding low-frequency components. Shimba[4] proposed a method for estimation of the trajectory of the 7 centre of gravity of the body from the rate of change of the angular momentum of the whole body, as obtained from force plate data. G. F. Harris[5] collected postural data from a force platform and analyzed body sway based on frequency consideration.

The main disadvantage of this method of recording and measuring body sway by using a force analysis platform is the high cost of the equipment. Vladimir [2] presented a simple technique for measuring and evaluating the stability of human upright posture based upon the measurement of the head sway. Head sway is relatively easy to measure, and the equipment required is much less expensive than a good force platform. The results obtained by this method provide, in principle, the same information about the posture control system, though the acquired data may appear in quite a different form. This method for recording and measuring postural sway has several advantages. It is simple and easy to transport and use, and it costs much less, in comparison, than a commercially available force platform and its associated equipment. It has sufficient sensitivity, accuracy and speed of operation, and there is no danger or discomfort for the investigated subject.

More elaborate methods of measurement of body movement are used to directly determine the trajectories of various parts of the body in the upright position.

Recently, standard cameras and high-speed cameras, associated with suitable devices for facilitating frame reading and digitizing the meaningful coordinates, have been largely used. Advanced transducer and microelectronics technology made it possible to develop the new systems for automatic body movement analysis. The Selspot[6] and

COSTEL[7] systems used light-emitting diodes (LED) as a transducer, which were fixed on the subject's chosen points, and then used linear CCD arrays to monitor body 8 sway. In both cases the wire and necessary hardware must be carried by the subject.

ELITE [8] system used small hemispherical passive markers, which were placed on

the relevant points of the body. A real-time processing of the TV images was used to

recognize multiple passive markers and compute their coordinates. This performance

was achieved by using a special algorithm allowing the recognition of markers only if

their shape matched a predetermined "mask".

All research mentioned above addressed a common interest in body sway.

Considering body movement during scanning in the Cyberware whole-body scanner,

Brunsman and Robinette [9] used a force analysis plate mounted on the scanner

platform to dynamically measure the displacement of the center of gravity of the

human body. Their study shows that the left-to-right sway was negligible compared to

resolution of the scanning system (5mm). The forward-to-backward sway, however,

may influence the quality of the scan. It is suggested to re-scan the object when the

standard derivations in forward-to-backward direction exceed 30mm. Additionally,

during the scan, attention must be paid to movements of body parts. If any doubt

arises, the scan should be redone.

Since one of the most important applications of a 3D whole body scanner is

personal clothing design and fit, obtaining the apparel measurement errors extracted

from 3D scans is imperative. In this thesis, Jack®2.1 is used to evaluate the apparel

measurement errors based on the results of the body sway.

As a product of the Center for Human Modeling and Simulation at the University

of Pennsylvania, Jack is a powerful human factors design and ergonomics visualization

2.] A registered trademark of the University ofPennsylvania, which refers to a software package. 9 software package that provides a 3D human model for predicting how a person will interact within a given system or environment.

The following is a list of main features of Jack[lO]:

--- Fully jointed human figure with real-time movement in three dimensions.

--- All parts can be programmed to move automatically.

--- Realistic degrees-of-freedom and joint limits.

--- Anthropometric scaling dri ven from spreadsheet.

--- Body balance control.

--- Eliminate expensive prototype building.

--- Powerful LISP/C&C++ programming interface for extending Jack's

functionality.

Jack ca~ help determine whether a human would fit comfortably in a system or environment. By using the simulated human to explore design alternatives with Jack, engineers can reduce the need to build costly and time-consuming prototypes. Analysis formerly accomplished painstakingly with blueprints, databases, and small plastic figures has been gradually replaced by dynamic 3D human modeling.

This paper presents a direct and effective research method to analyze body sway during scanning for a Cyberware whole-body scanner based on 3D data processing. A software simulation and analysis using Jack model is developed to estimate the anthropometric measurement errors resulting from body sway. 10 CHAPTER THREE

BODY SWAY ANALYSIS IN CYBERWARE WB4 SCANNING

3.0 Introduction

The previous research methods for body sway analysis are reviewed in Chapter 2.

Among them, only the research of Brunsman and Robinette[9] directly concentrated on the effect of body movement during scanning for a Cyberware whole-body scanner. As we know, the force analysis platform and its associated equipments used by Brunsman and Robinette are very expensive. This chapter presents a new method for analyzing body sway in Cyberware WB4 scanning, based on 3D data processing technology. A cylinder is attached to the human body during scanning and 3D data is collected by a Cyberware

WB4 scanner, which includes both body surface data and cylinder surface data. The body sway of the subject during scanning will cause discontinuities both in body surface data and in cylinder surface data. By analyzing the cylinder surface data, body sway in scanning can be determined.

3.1 Analysis Method

3.1.0 The Cyberware Whole Body Scanner

The Cyberware whole body scanner is used to acquire the shape information of the entire human body. To capture the intricacies of the human body in one pass, the

Cyberware whole body scanner uses four scanning instruments mounted on two vertical towers (Figure 3.1). With the subject standing on the scanner's platform, the scanning instruments start at the head and move down to scan the entire body. A primary goal of 11

Figure 3.1 --- The Cyberware whole body scanner the whole body scanner is to acquire as complete a model as possible in one pass. The use of four scanning heads improves accuracy on the sides of body and in difficult-to-reach areas, such as under the arms.

Although the whole body scanner is designed to handle many different poses for a wide range of applications, the simple anthropometric pose gives the best results. Figure

3.2 shows US Air Force's Computerized Anthropometric Research and Design Lab using the Cyberware whole body scanner to scan the human body with a simple anthropometric pose. They use these scan data to develop better-fitting protective equipment.

3.1.1 Scan the Subject with the Cylinder Attached

From 3D data processing, the effect of body sway in scanning may be measured by analyzing 3D data of an object of known geometry captured by the whole body 3D 12

Figure 3.2 --- The researcher uses Cyberware WB4 scanner to collect the human body anthropometric data in a simple pose. digitizer. Since it is difficult to know the geometry of a human body accurately, a cylinder was attached to the body during scanning.

To capture body sway, a cylinder 917 mm long and 78 mm in diameter was attached to the front torso of a subject using cardboard supports (Figure 3.3) and was made as vertical as possible in scanning using a level. An Openlnventor'< data file, which

3 shows both body surface and cylinder surface, is generated by CyScan .3 . Then the human subject and stand-off supports must be edited out so that only the cylinder surface

3 remains (Figure 3.4). CyEat .4 is used to generate a Ply3.5 data file, which only shows the cylinder surface. Finally, coordinate data is extracted from the Ply file and saved as an

ASCII file for further 3D data processing and analysis.

3.2 A graphics file format developed by The Silicon Graphics Inc. 3.3 A software developed by Cyberware Inc. 3.4 A software developed by Cyberware Inc. 3.5 A polygon mesh file format used by the Silicon Graphics ZipPack program. 13

Figure 3.3 Subject with cylinder attached Figure 3.4 Cylinder extracted to his front torso showing scanning position. whole body scan. Wavy shape caused by deliberate body sway.

3.1.2 Post-Processing of 3D Cylinder Surface Data

For the Cyberware WB4 scanner, the vertical increment is 2 mm from top to bottom during scanning. In another words, the cylinder surface data is collected every 2 14 mm vertically by the scanner. The result is a series of slices (refereed to a z-slices)

through the cylinder, and each slice represents what is captured by the scanner as the

plane of laser light passes over the subject. To find a method to analyze the cylinder

3 surface data, a program 'drawslice', written in C and OpenGI .l , displays each slice of the cylinder in two-dimensions from top to bottom. Figure 3.5 shows an actual z-slice of the

cylinder data in two dimensions. Although the tube was attached to the subject using the supports that allow the cylinder to stand away from the body to minimize occluded areas, the cylinder parts which are close to the subject are still hidden from the scan headers.

Missing data can't be completely avoided. Each z-slice is no longer a complete circle

(Figure 3.5).

.. ..

......

Figure 3.5 An actual z-slice of the cylinder in 2-D.

The best way to visualize the effects of movement on cylinder shape in scanning is to envision a stack of coins placed with their centers aligned or stacked so that their centers are shifted from frontlback and side/side. Thus, the cylinder movement can be determined by investigating the slice-shift. In order to obtain the slice shift relative to one

3.1 The Graphics Library used in SGI. 15 another, a simple and effective way is to trace the variation of the same position point through all slices.

By analyzing cylinder data z-slice by z-slice using the program 'drawslice', we found that data missing and noising problems can not be avoided even when the card supports are used. These problems become very serious especially in the cylinder parts in which the card supports are fixed [Figure 3.3]. To overcome data missing and noising problems, the 'furthest point analysis algorithm' is developed to analyze body sway from the 3D scan data.

The point P (cross-mark in Figure 3.5) -- the furthest point in X-direction away from the subject -- is traced through all slices. Theoretically if no body sway occurs, the point P (Figure 3.5) for all slices should be coincident to a vertical line. Body sway will move the point P from slice to slice. Thus body sway can be measured as a variation in X

(forward/back) and Y (side/side) coordinate values for the point P among all the Z slices.

If the subject does not sway, the X values should be almost the same (allowing machine error), and this applies for Y values as well. Any movement shifts point P's X and Y coordinates front/back or side/side relative to one another.

How to ~ompute the point P's X and Y coordinates for each slice? Assuming

there are m data points in one z-slice: [X, ' Yo]' [X 1 ' Y 1 ], [X 2 ' Y 2] ••• [X m- l , Y m-l].

The following five steps are used to find out the point P's X and Y coordinates from these m data points.

1) The X-average from the m data points is calculated. m-l LXi X = i=O m 16

+1{ .. A . .- .. c ·

. ..x +x M + y=(Ay+ByY2 X=X -...... ~ (a)

Figure 3.6 A diagram which shows how to compute the point P's X and Y coordinates. (a) Sample z-slice. (b) Points whose X value is greater than a x-average are discarded. Point M is midway between A and B, and point P is midway along arc AB. Sway is measured as a variation in X and Y coordinates of point P. 2) Among the m points of each slice (Figure 3.6(a», the points whose X is less than or equal to X are kept. The n data points whose X ~ X come from the cylinder surface which is far away from the subject, hence the noise which occur near the subject is avoided (Figure 3.6(b».

3) Assuming the n points are expressed as [X ~ ,Y ~], [X ~ ,Y ~], [X ~ ,Y; ]

[X ~-l ,Y ~-l ]. From the n points, the point A and B which have y maximum and minimum are searched out. The point M (Figure 3.6(b» is the midpoint between A and B and its coordinate is 17 4) The n points are divided into two parts using the horizontal line. Distances

[dao. dal.da2....] from each point to the line are calculated. Points C and D are closest to the line, but are on opposite sides.

5) The point P is found midway between C and D (Figure 3.6(b». The point P is considered as the farthest point from the subject for each slice. The above procedures (1 -

5) are used to get the point P(z) for all the z-slices. Thus, the following matrix can be obtained:

Px(zO),Py(zO),zO Px(zl),Py(zl),zl Px(z2), Py(z2),z2 Px(z3), Py(z3), z3 Px(z4), Py(z4),z4

From the above matrix, the curves of Px(z;) - z, and Py(z;) - z, can be drawn.

These two curves will show the forward/backward and side/side body movement, respectively.

3.1 Software Implementation

3.2.0 Data Sort by Z Coordinate

The cylinder surface data file, which is edited out from the subject and cardboard supports by Cyberware's CyEat, is in Ply file format. In order to analyze the cylinder movement using 3D data processing, this Ply file must be converted to ASCII file format. 18 The function 'plyLoad(...)' in plyload.c [refer to Appendix 1.2] implements this file

conversion and saves this ASCn file as 'orig.ascii'.

The extracted data in the ASCII file 'orig.ascii' is out of order in the z coordinate.

To analyze the tube movement z-slice by z-slice, the tube coordinate data must be sorted

by z and organized into 2mm slices from top to bottom, as defined by the Cyberware

whole-body scanner. All the data points with the same z-coordinate must be grouped

together.

The function 'dataSortByZ(), in the file 'dataSortByZ.c' implements the data sort

(refer to Appendix 1.3). Due to the huge number of data points in the file 'orig.ascii', memory map 'mmap(...)' is used to map all the data in 'orig.ascii' into memory. Thus, frequently reading the file is avoided and program speed is increased. A binary search tree is used to sort the data by z.

3.2.1 Implementing Furthest Point Analysis Algorithm

As stated in Section 3.1.3, half of each z-slice is thrown away in order to avoid data missing and noise problems. The number of z-slice points in file 'data.ascii' is calculated by function 'dataStatistic()' in file 'dataStatistic.c' (Appendix 1.3). This result is used to read the data points slice by slice from the file 'data.ascii'.

Once each slice data is read from the file, the average of its x-coordinates is calculated by the function 'average(...)'(Appendix 1.3). A file 'cutoff.ascii' is generated which only contains the points whose x-coordinates are less than or equal to x-average.

Figure 3.6(b) shows these data points of an actual z-slice.

The functions 'find_min(...)' and 'find_max(...)' are used to search the point A and B for each slice(Figure 3.6(b». Each slice is then divided into an upper part and 19 lower part, from which the point C and D (Figure 3.6(b» are found. The middle point between C and D for each slice is considered as the furthest point away from the body in x-direction. A linked-list (Figure 3.7) is used to store the furthest point of each z-slice.

0 - zO - z1 ~ - z 0 (xO,yO) (x1,y1) (x,y)

*head - *next - *next I-- - NULL

Figure 3.7 --- A linked list to store the farthest point for all z-slices.

3.3 Verification of the Analysis Method and its Software Implementation

In order to prove the analysis method and its software implementation, five scans are taken from a cylinder 917mm long and 78mm in diameter: One is from a static cylinder resting on the scanning platform. Its scan data is displayed in figure 3.8, which shows a vertical cylinder. Two are from a moving cylinder fixed on a movable device, which is connected to one of four scanner heads. These two scan data are displayed in

Figure 3.9, which shows the variation of each slice of the cylinder. The other two are from the intentional body sway of a subject holding a cylinder close to the body (Figure

3.6(b». The 'further point analysis algorithm' is used to analyze these five scan data.

Theoretically, for a static, exactly vertical cylinder, the graphs should be exactly horizontal. From Figure 3.10, the actual scan graphs form almost a perfect horizontal line.

Scan errors and data processing cause only two jumps in the graphs.

Figures 3.11 and 3.12 show the moving cylinder scans. During scanning, the cylinder is fixed on a movable frame, which is connected to one of the scan heads. For the

Cyberware scanner, the scan height is 2.045 meters in 17 seconds. The time the scan heads scan the 917mm long cylinder is 20

Figure 3.8 A static cylinder is scanned

Figure 3.9 A moving cylinder is scanned 21

(a) forward/backward movement

160 I I I I ..-.. E S 150~ - ...... c:: CD ~ ECD 140 - U ctS c.. .~ 130- -. "'C x 120 I I I I -1000 -800 -600 -400 -200 0 z direction (mm) (b) side/side movement

210 I I ..-... E S200- - ...... I c:: CD ~ 190- - o ctS c.. .~ 180- - "'C ~ 170 I I I I -1000 -800 -600 -400 -200 0 z direction (mm)

Figure 3.10 --- A static cylinder is scanned for (a) forward/backward Movement and (b) side/side movement. 22

(a) forward/backward movement 200 r------.,r--"--~------r---____r---____r_---___, E g 0 c CD ~ -200 o (lj Cl. .~ -400 -c x

-600 a....---__--'--__---'- ""'---__--'--__----'-__~ -1000 -800 -600 -400 -200 o 200 z di rection (mm) (b) side/side movement 400 r---oo----.------or--o-----.------.------, E g 200 C Q)

EQ) 0 o (lj Cl. .~ -200 -c >.

-400 a....------'- .a.------'-__~ -1000 -800 -600 -400 -200 o 200 z direction (mm)

Figure 3.11 --- A moving cylinder is scanned for (a) forward/backward Movement and (b) side/side movement. 23

(a) forward/backward movement 200 -----...,..----....----...------...------. E E "'-'" C 0 Q) E Q) o ~ o, -200 en -c x -400 '------~----I----"'------"'------' -1000 -800 -600 -400 -200 o 200 z direction (mm) (b) side/side movement 400...------...----.,------r------r------, E g 200 C Q)

EQ) 0 o ~ c.. .s -200 -c ~

-400 '----__---'--__---&. ---i.. ~____' -1000 -800 -600 -400 -200 o 200 z direction (mm)

Figure 3.12 --- A moving cylinder is scanned for (a) forwardlbackward Movement and (b) side/side movement. 24

917mm/12045 x 17 second --.762second

The total expected movement should be 2045mm / 17 secx 7.62 sec =914mm .

From Figures 3.11 and 3.12, the total x-displacement of the cylinder is about 600 mm and the total y-displacement of the cylinder is about 700 mm. The total movement in scanning is.J6002 +7002 = 921 mm. This value compares favorably for the 'furthest point analysis algorithm' .

Two scans were taken from the intentional body sway of a subject holding a cylinder close to the body. (Figures 3.13 and 3.14). During these two scans, the subject produced intentional body sway both in front/back and in side/side directions. From

Figures 3.13 and 3.14, the shape of the graphs obviously show the wave characteristics in both x and y direction. The displacements in x and yare greater than 80mm, which are attributed to intentional body sway. In this respect, the 'furthest point analysis algorithm' is proven to give reasonable and correct results. 25

(a) forward/backward movement -250 ...... E E "-"" ...-c Q) ~ -300 o nj c. en -c x -350 -400 -200 0 200 400 600 z direction (mm) (b) side/side movement -60 ...... E E "-"" -80 ...-c Q) ~ -100 o nj c. .~ -120 -c ~ -140 -400 -200 0 200 400 600 z direction (mm)

Figure 3.13 --- Scan a cylinder with the subject's intentional sway for (a)

forward/backward movement and (b) side/side movement. 26

(a) forward/backward movement -260 ..-..... E £-280 ..., c Q)

EQ) -300 o ccs 0.. .~ -320 ""0 x -340 -400 -200 0 200 400 600 z direction (mm) (b) side/side movement -60 ..-..... E ...... E -80 C Q)

EQ) -100 o ccs 0.. .~ -120 ""0 ~ -140 -400 -200 0 200 400 600 z direction (mm)

Figure 3.14 --- Scan a cylinder with the subject's intentional sway for (a)

forward/backward movement and (b) side/side movement. 27 CHAPTER FOUR

SIMULATION AND ANALYSIS OF BODY SWAY USING

JACK PACKAGE

4.0 Introduction

As stated in Chapter One, the Cyberware whole-body scanner was developed to obtain anthropometric measurement data. However, body sway in scanning causes discontinuities in the 3D data. This, in tum, causes anthropometric measurement errors.

In the previous chapter, the method for determining body sway in scanning was presented. In this chapter, a human body model is developed using the Jack Software

Package to simulate body sway. The relationship between the movement of the center of gravity and anthropometric measurement errors is analyzed using the model.

4.1 Develop the Human Body Model Using Jack

4.1.0 Peabody Object Representation

Jack is an interactive system for constructing and manipulating Peabody objects. It is crucial to understand Peabody before using Jack, since so many of the features of Jack deal intrinsically with Peabody objects and rely heavily on the syntax of the Peabody language.

Peabody is a representation for complex articulated geometric objects. It represents figures composed of segments connected by joints under the influence of constraints. The syntax of the Peabody language somewhat resembles a programming language, except that it defines static elements, not actions. There are many basic 28 declarations for constructing a human body model such as figure, segment, joint, site, node, etc. The homogenous transformations are also supported by Peabody language.

Like other programming languages, Peabody language has its own keyword and arithmetic expressions. Peabody is used to define figures in special figure files.

4.1.1 Develop a Model Based on Peabody Language

Jack provides a command called 'Create Human Figure', which creates a Peabody figure file that can be recognized as the human model figure file by Jack. With 'Create

Human Figure', one figure file, 'Jack.fig', is generated, which consists of 77 segments,

294 sites, 76 joints, and 155 degrees of freedom.

In order to develop a model that looks like a human standing still in the

Cyberware WB4 scanner, the model must maintain a posture with arms extended. A

Peabody environment file called 'Jack.env' needs to be generated, which contains

'jack.fig' file, based on the syntax of Peabody language. Furthermore, 'Jack.env' also includes information about model posture, attribute, etc. When 'Jack.env' is read by

Jack, a human model in the anthopometric stance will appear in Jack_Window (refer to

Figure 4.1).

4.2 Software Simulation of Body Movement Using the Model

4.2.0 Introduction

Jack can simulate a variety of subject movements. Jack also provides a very powerful Lisp/C&C++ programming interface, which can be used to develop some special applications. In order to simulate body sway, appropriate movement functions must be developed based on Jack's Lisp/C&C++ programming interface. 29

Figure 4.1 -- Jack Model

4.2.1 Lisp Interface and JCL

Lisp supports symbol and list processing, higher-order functions, lexical closures, and a variety of other advanced programming techniques. Data structures are also very easy to build in Lisp. Lisp manages memory automatically and has built-in lists, vectors, and matrices. The Lisp interface to Jack allows general programming of Jack internals and simplifies Jack development.

JCL stands for Jack Command Language, which is a "scripts" of Jack Commands.

Operations, which may be performed interactively in Jack, may also be performed using

JCL. A JCL callout mechanism, provided by Lisp interface 'rawjcl', allows any JCL to be evaluated. This function takes a string argument and executes it as Peabody code.

4.2.2 C&C++ API

Jack provides a C/C++ API (Application Interface) that allows the majority of

Jack's functionality to be accessed from any C/C++ program. The functions provided by 30 the C API use RPC calls to communicate with a Jack process running on any host accessible to the local host.

RPC (Remote Procedure Call) uses TCP/IP protocol to implement message transportation between a server process and a client process. Remote procedure calls differ from local procedure calls by

1. Error handling: failures of the remote server or network must be handled when

using remote procedure calls.

2. Global variables and side-effects: since the server does not have access to the

client's address space, hidden arguments cannot be passed as global variables

or returned as side-effects.

3. Performance: remote procedures usually operate one or more orders of

magnitude slower than local procedure calls.

4. Authentication: since remote procedure calls can be transported over

unsecured networks, authentication may be necessary. Authentication prevents

one entity from masquerading as some other entity.

Jack provides a function 'Jackrpc_init(...)' to implement the RPC connection between Jack server process and client process. After the RPC connection is established all C/C++ application functions can be accessed directly.

4.2.3 Network Jack

Jack can allow an external process to control and query Jack. Two Jack processes, each running on a separate terminal, can communicate with each other. These two processes share the same environment. The figure in one terminal can be controlled by 31 one Jack process running on another terminal, Implementation uses TCPIIP stream sockets to transmit messages back and forth.

A Jack process, which is used to control the figure in the environment, is considered a 'player'. It is echoed by another Jack process, which is considered a 'ghost'.

The normal cycle of message between a 'player' and its 'ghost' is

--- 'player' changes position or posture and sends a message to its 'ghost'.

--- 'ghost' receives the messages and updates the position or posture.

--- 'ghost' sends a reply message to 'player' telling it it's ok to send more posture

update messages. 'player' will not send any more updates until this reply is

received. This will keep the two Jack processes roughly in sync.

Terminal A Terminal B TCP/IP connection ...... Server .... Client Process message transmit by Process ...... 'ghost' Oy.K..t'L .... 'player'

C/C++ API .....

..... Lisp Interface JCL

Figure 4.2 --- Network Jack and its implementation

Figure 4.2 shows the relationship between 'player' and 'ghost'. The connection between them is based on TCP/IP protocol. RPC is used to transmit messages back and forth. After the RPC connection is established, all CIC++ API can be used to control the model in server side. List interface and JCLs are also used to control the model in server side by 'Jacklisp(...)' and 'Jackjcl(...)', respectively.

4.2.4 Software Simulation Methods 32 With Jack Lisp interface and C/C++ API, a software program 'jackmove' was developed to simulate and analyze body sway based on a human model. In order to run this program, the Jack server process is run in one terminal and Jack Model (Figure 4.1) is read in Jack_Window. 'jackmove' is run in another terminal as the client process.

Thus, 'jackmove' can control and simulate the human model movement in Jack_Window.

In order to analyze body movements, eight principal positions are chosen: wrist, elbow, shoulder, head, chest, abdomen, upper leg, and lower leg. First, all coordinates of these eight positions are picked as [Xo,Yo,Zo], [Xl,Yl,ZI]...[X7,Y7,Z7], After the specific movement is specified, the new coordinates can be obtained: [X'o.Y'o.Z'o],

[X'I,Y'I,Z'I]...[X'7,Y'7,Z'7]. The movement of one position is calculated as

(4.3.1)

As far as the calculation of apparel errors (the left inseam, for example), initial length is computed based on two positions (assuming A and B): [X a' Y" .z,],[Xb' J:, z.]

(4.3.2)

After the movement is specified, the new coordinates of position A and B become

[X~, Y,,' ,ZJ,[ X~, J:' ,Z~]. The new length is calculated as

(4.3.3)

Thus,

apparel error =Inew_length - initital_lengthl (4.3.4)

A simple user-interface is designed in order to easily run 'jackrnove'. First, the user needs to specify the kind of the movement. Second, the user needs to specify the 33 kind of measurement. To run 'jackmove' in detail, the user can just follow the directions

in the menu, and the final results will be obtained.

4.3 Software Implementation of 'jackmove'

4.3.0 Introduction

The software implementation of 'jackmove' can be divided into three parts:

1. Specify and implement the model movement. It consists of two files

move_center_gravity.c and adjustJoint.c.

2. Specify and implement measurement. It consists of the following files:

dataInit.c, Initial_Iength.c, picknewpoint.c, showlengtherror.c,

showmovement.c, and shownode.c.

3. User interface. It consists of three ~ files: mainmenu.c, jointmenu.c, and

nodemenu.c.

4.3.1 Establish RPC connection between Jack Program and 'jackmove' program

First, the command 'jack -e c_api' is run to start Jack server process with TCP/IP

socket port opened in one terminal. In another terminal, 'jackmove' is run. With the

'JACKrpc_init(...)', 'jackmove' can communicate with the Jack server process using

RPC. Once the RPC connection is established, all the C/C++ API can be used to control

the model in server side.

In Section 4.2.2, the file 'jack.env', which contains 'jack.fig', is created and stored

In directory '-/jack'. Once the 'JACKjcl("read_file(\"-/jackljack.env"); TRUE)' in

maine) is called [refer to Appendix 2.1], the 'jack.env' will be read and a human model will appear in Jack_Window (refer to Figure 4.1). In order to simulate body sway, the 34 model balance control is set to "hold current position" by calling

'JACKjcl("set_balance_control(\"jack\",\"hold·current position',");", TRUE)'.

4.3.2 Specify the Movement of the Center of Gravity

Each figure has a balance point, which is the vertical projection of the figure's

center of gravity (or center of mass) onto the ground plane. Jack provides a JCL

'move_center_of_mass(...)' to allow one to change the balance point of the figure. As

mentioned in Chapter 2, body sway is a kind of compensatory movement to ensure the

maintenance of posture balance. So this function can be used to simulate body sway

behaviors by changing the balance point. The function move_center_gravity() (refer to

Appendix 2.2) implements the movement of balance point and simulates body sway.

move_center_of_mass(human, endjxform):

This JCL repositions human to put the center ofmass at end_xform.

Args: human - a human figure name string.

end_xfarm - A transform indicating the end position and orientation of

center ofmass in global coordinates.

The model's original coordinates of the center of gravity are (-8.50cm, 112.37cm,

-8.51cm). The side-to-side movement of the model is specified by changing the x­ coordinate of the center of gravity. The forward-to-backward movement of the model is specified by changing z-coordinates. Y-coordinate represents the height of center of gravity and does not need to be changed.

Before changes to the center of gravity are specified, the model should be repositioned to the original posture. Thus the measurement results for different kinds of movement are based on the same posture. 35 4.3.3 Adjust Joint

Human body consists of many joints, which contribute to body part movements.

Each joint has its own degree of freedom and its initial joint angles. By changing the joint angles, the movement of body parts is implemented and analyzed. For example, if elbow joint angles are changed, the front arm will move accordingly.

The function 'adjustJoint()' implements the above joint adjustment (refer to

Appendix 2.3). In adjustJoint(), three C API functions need to be explained in detail:

1. JACKfigure-find(figname, figure, maxfigures).

This function is used to find a pointer to a single figure.

Args: Char *figname - name offigure to find.

Jackptr *figure - output array for figure when looking for a single figure, it

can just be the address ofa Jackptr.

Int maxfigures - maximun number offigure pointers to put in figures array.

Should be 1 when looking for one figure.

2. JA CKfigure...iointifigptr, jointname.joints,maxjoints):

This function is used to get Jack joints if given a figure pointer.

Args: Jackptrfigptr - pointer to Jackfigure.

Char *jointname - name ofthe joint.

Jackptr *joints - output array for joint pointers. Ifonly a single joint is to

be returned, this can just be the address ofa Jackptr.

Int maxjoints - length of joint array should be 1 when doing a single

joint query and passing the address ofa Jackptr as joints.

3. JACKjoint_angles(jointptr, angles, maxangles,jlags): 36 This function is used to set or obtain the current joint angles for every

degree-of-freedom of a joint. All angles are in radians.

Args: Jackptr jointptr - pointer to a Jack joint.

Float *angles - if setting joint angles, then this is the input array of new

joint angles for each degree offreedom for the joint. If getting angles, then

the current angles for each degree offreedom ofthe joint will be put in this

array.

Int maxangles - if setting angles, this should be set to the number of valid

available values in the angles array. If getting joint angles, this should be

the size ofthe angles array.

The above three C API functions are used to control the joint movement. With

'JACKfigure_find("jack",&jackptr,1)' (refer to Appendix 2.3), a Jack figure pointer

'Jackptr' which points to the Jack model is obtained. With the 'Jackfigurejoint(Jackptr, jointname, &jointptr, 1)', a different joint pointer, 'jointptr', is accessed from a different joint name. Finally, with the 'JACKjoint_angles(...)', either old joint angles are accessed or new joint angles are set. When new joint angles are set, the model will do the corresponding movement. The new joint angles can be input from the keyboard. In other words, the joint movement can be controlled interactively.

4.3.4 Initialize Node Position and Apparel Length

The model in Figure 4.1 contains 77 segments. Each segment consists of a number of nodes, which can be used to specify a specific location on the human body.

The Jack provides a JCL 'node_info(...)', which puts the node information into the

Jack_Message_Window. The node information includes the local coordinates, global 37 coordinates, etc. Among the node information, the node's global coordinates are the most important for specifying the movement measurement. Thirteen nodes are chosen to specify movement measurement and apparel measurement errors (refer to Appendix 2.4).

The function 'dataInit()' is used to initialize all node's global coordinates. With

Jack Lisp interface 'JACKlisp(...)', The JCL 'node_info(..)' is called and the node information is displayed in Jack_Massage_Window.

JACKlisp(instr, outstr, maxsz): lisp interface function call. Args: Char *instr --- a string oflisp code. Char *outstr --- outputfor result ofevaluating 'instr'. Int maxsz --- maximum number of char to put in 'outstr'.

Each 'node_info(...)' call will display six lines of information In

Jack_Message_Window, one of which is the node global coordinates. At the same time, a

'.jack.log' file is created by Jack to store all the information displayed in

Jack_Message_Window. Once problems occur when running Jack, this '.jack.log' file can be used to debug the problems. Through'.jack.log' file, the node's global coordinates can be obtained.

The 'initial_Iength()' (refer to Appendix 2.5) initializes the apparel lengths. Seven apparel lengths are chosen: sleeve inseam, leg inseam, leg outseam, waist height, shoulder height, neck height, and stature height. Using equation (4.3.2), each apparel length is calculated by choosing proper nodes.

4.3.5 Analyze the Body Movement

The eight specific locations on the model are chosen to approximately analyze the body movement: wrist, elbow, shoulder, head, chest, abdomen, upper leg and lower leg. 38 Once the body movement is specified, one of the locations is selected and its movement is computed.

The function 'picknewpoint(... )' (refer to Appendix 2.6) will give the new coordinates for a specified location after a body movement. The new coordinates come from the file '.jack.log'. In 'picknewpoint(...)', the variable 'position' is defined as a global static variable which is used to record the previous reading position for the file

'.jack.1og'. When the JCL 'node_info(...)' is called, the file '.jack.log' will be updated and the another six-line node information will be appended to the previous file,

'.jack.log'. Thus the new node's global coordinates can be read.

Once the new global coordinates are obtained, the movement for the specific location can be computed. In function 'showmovement()' (refer to Appendix 2.7), the distance between the new position and the original position are calculated using Equation

(4.3.1). This distance is considered as the body part movement caused by the specified body movement.

4.3.6 Analyze the Apparel Measurement Error

The eight apparel measurement chosen are: sleeve inseam, leg inseam, leg outseam, waist height, shoulder height, neck height, and stature height. The measurement errors of these apparel lengths are calculated in function 'showlengtherrort)'.

In 'showlengtherror()' (refer to Appendix 2.8), the 'sleeve inseam' measurement error is calculated first. The new coordinates for 'wrist' are picked up with function

'picknewpoint()'. The length between 'new wrist' and 'old shoulder' is calculated using equation (4.3.4) as new measurement length. The difference between the new 39 measurement length and the original length is considered as the maximum measurement error of 'sleeve inseam'.

The method which is used to compute the other apparel length measurement errors is similar to the above. The only difference is that the proper nodes are needed when a new measurement length is computed.

4.3.7 User Interface

A simple user interface is designed to allow user to run 'jackmove'. The user simply follows each menu and selects the proper item. Figure 4.3 shows the main menu.

Either the movement of the center of gravity or the movement of body parts can be specified. Once the movement of the center of gravity is chosen, the user needs to input a quantity for frontlback and side/side movement. The Jack Model (Figure 4.1) in

Jack_Window will display the corresponding movement. If the movement of body parts is specified, a second menu pops up (Figure 4.4) that presents six main body joints: elbow, shoulder, hip, knee, neck, and waist. Each joint has different degrees of freedom similar to the actual human body. When joint angles are changed, the Jack Model in

Jack_Window adjusts its body joint, correspondingly. Figure 4.5 shows the measurement menu. After a movement is complete, eight specific position movements or apparel measurement can be selected. For the position movement, eight body positions can be chosen: left wrist, left elbow, left shoulder, head, chest, abdomen, left upper leg, and left lower leg. For the apparel measurement errors, seven simple anthropometric specifications are calculated: sleeve inseam error, leg inseam error, leg outseam error, waist height error, shoulder height error, neck height error, and stature height error. HUMAN BODY MOVEMENT ANALYSIS PROGRAM -

0: MOVE CENTER OF GRAVITY 1: MOVE HUMAN BODY PARTS

q: QUIT

ENTER YOUR SELECTION?

.., '....

Figure 4.3 User Interface I

o+::­ ****************************************** * * * MENU FOR ADJUST BODY JOINTS * * * ******************************************

0: Adjust LEFT_ELBOW 1: Adjust LEFT_SHOULDER 2: Adjust LEFT_HIP 3: Adjust LEFT_KNEE 4: Adjust NECK 5: Adjust WAIST

r: Return previous menu

Enter your selection?

Figure 4.4 User Interface IT

~

~

N

$$

IN

INTERESTED

ARE

YOU

LEG

LEG

ITEM

menu

UPPER LOWER

SHOULDER

WRIST

ELBOW

selection?

previous

ill

LEFf

ABDOMAN

LEFf

CHEST

HEAD

LEFf

LEFf

LEFf

FOLLOWING

your

Return

APPARELEEROR

Select

Select

Select

Select

Select

Select

Select

Select

Interface

THE

10.

Enter

9.

8.

7.

6. 5.

1.

3. 4.

2.

User

PICK

4.5

$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$

$$

$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$

Figure " 43 CHAPTER FIVE

RESULTS

A method to determine body sway in Cyberware WB4 scanning was described in

Chapter Three. In order to analyze actual body sway, 3D digitizing data needs to be collected from a subject, fitted with a cylinder, in a relaxed standing position. Five scans were taken of the subject with the cylinder adjusted vertically between each scan. The cylinder surface data were extracted from these five scans. The 'furthest point analysis algorithm' in Chapter Three was applied to analyze the subject sway from each scan, respectively. After the body movements are found, the anthropometric measurement errors resulting from these movements were analyzed using the methods in Chapter Four.

Figures 5.1-5.5 display graphs from the five scans based on the methods in

Chapter Three. Comparing the five graphs, for x-coordinate variation (e.g. frontlback movement), SCANl, SCAN2 and SCAN4 have more-or-less linear tendency. SCAN3 and SCANS have a bit of the sinusoidal wave shape but the range is very limited. For y­ coordinate variation (e.g. side/side movement), SCAN2 shows a bit of a linear tendency.

SCANS shows a small wave shape. The other three scans are indistinguishable from scan noise.

From the five scans, the linear-tendency is considered as small body movement in the same direction during scanning. The wave-shape is considered as small body sway.

Besides body sway/movement, three other factors also affect these scan graphs. One is that the cylinder attached to the subject is not exactly vertical. The basic assumption of 44

(a) forward/backward movement -230...------,.-----.,------r-----.------, E ...... E -240 C Q) ~ -250 o (lj 0.. .~ -260 -c x

-270 '------'----__..&.-- -...- ..&-.- -J -400 -200 o 200 400 600 z direction (mm) (b) side/side movement

-200 o 200 400 z direction (mm)

Figure 5.1 --- First scan of the subject, fitted with vertical cylinder 45

(a) forward/backward movement -355 -----....-----....------..----.,..------,------, E-360 E i-365 Q) ~ -370 o ~-375 (f) ~ -380

-385 "--__....&.-__--"-- L..-- -&.-__---' -400 -200 o 200 400 600 800 z direction (mm) (b) side/side movement -105 r------r"---__...._-----..----~--___,r------,

E -110 E i -115 Q) ~ -120 o ~-125 (f) ~-130

-135 a..-- &...--....&.-__---'- '--__-"---__--'--__---' -400 -200 o 200 400 600 800 z direction (mm)

Figure 5.2 --- The second scan of the subject, fitted with vertical cylinder 46

(a) forward/backward movement -320 ----~---~----,------___r_---____:'1 f-321 '-""" "E Q) -322 E Q) ~ -323 C­en :.c -324 x

-325 L-- --L- ...L.- ----'- ---'-- ---' -400 -200 o 200 400 600 z direction (mm) (b) side/side movement

-68 I I I ~ ...-- ~ r-' .-L - I-70 - - '-""" C Q) -72 I- - E ...--- a.---- ~ Q) ~ -74 ~ - c..en ~ -76 ... - ~

-78 - I I I I -400 -200 o 200 400 600 z direction (mm)

Figure 5.3 --- The third scan of the subject, fitted with vertical cylinder 47

(a) forward/backward movement -270,..------...------r-----.,.------,------, 1-275 "-""....., s-280 E Q) ~ -285 C­ en =0 -290 x

_'~ -295 i-----'--_ ___'I...._.______..IO""'______.l....._._____..I -400 -200 o 200 400 600 z direction (mm) (b) side/side movement -46 ,..------...------r----~----~-----.,

E-48 E ~-50 Q)

EQ) -52 o (lj c.-54 en ~-56

-200 o 200 400 z direction (mm)

Figure 5.4 --- The fourth scan of the subject, fitted with vertical cylinder 48

(a) forward/backward movement -235 _-----r------yo------y------,------..., E E ""-"" C -240 Q) E Q) o Cd 0.-245 en :.c x -250'------.a...-----.....L------"------"------' -400 -200 o 200 400 600 z direction (mm) (b) side/side movement -65 ------....------..-----....------,..------. E ""-,,,,-70E ..- c Q) E Q) -75 o Cd c. .~ -80 "'C ~

-85 ""---__--.-Ir....-- Ioo.-__--.-IIoo.- '---__----' -400 -200 o 200 400 600 z direction (mm)

Figure 5.5 --- The fifth scan of the subject, fitted with vertical cylinder 49 the analysis method in Chapter Three is that the cylinder attached to the human body should be vertical like a stack of coins with their centers aligned. If the cylinder is not vertical, the graphs will show a linear upward/downward tendency. The cylinder must be adjusted vertically between five scans in order to maintain the same initial condition for each scan. The other two factors are machine scan errors and 3D data post-processing errors.

Table 1 gives the body sway/movement magnitudes in front/back and side/side directions from the five scans. These values are attributed to body sway/movement confounded with machine scan error, post-processing error, and not-exactly vertical cylinder. Although each contribution from the above factors can't be determined exactly,

The maximum magnitudes of body sway in front/back and side/side directions can be estimated.

Body sway/movement does occur within the five scans. Chapter Four presents software simulation and analysis of body sway using Jack. This method can be used to analyze the movement of the center of gravity and the movement of body parts. The anthropometric measurement errors can be calculated from the body movement.

Jack model is designed based on an average person's dimensions. Hence the difference in range between a Jack model and any scan subject is similar. The results in

Table 1 give the estimation of the maximum of body sway and the movement of the center of gravity. 50 Table 1 --- Body Sway from the Five Scans

Frontlback sway (mm) Side/side sway (mm)

Scan 1 20 -0

Scan 2 25 15

Scan 3 -0 -0

Scan 4 20 -0

Scan 5 10 10

Table 2 --- Anthropometric Measurement Errors from the Five Scans

Scan 1 Scan 2 Scan 3 Scan 4 Scan 5

Sleeve Inseam Error 0.15 em 0.37 em 0.00 em 0.35 em 0.09 em

Leg Inseam Error 0.06 em 0.15 em 0.00 em 0.07 em 0.03 em

Leg Outseam Error 0.06 em 0.25 em 0.00 em 0.08 em 0.04 em

Waist Height Error 0.22 em 0.64 em 0.00 em 0.31 em 0.19 em

Shoulder Height Error 0.05 em 0.36 em 0.00 em 0.06 em 0.06 em

Neek Height Error 0.01 em 0.00 em 0.00 em 0.01 em 0.05 em

Stature Height Error 0.01 em 0.14 em 0.00 em 0.02 em 0.06 em

Table 2 shows the anthropometric measurement errors based on the data in Table­

1 using the software simulation and analysis method in Chapter Four. From this table, the anthropometric measurement errors are v~ry small. In other words, body sway doesn't impact anthropometric measurement significantly. This result is similar to the reports 51 5 1 from Robert Beecher . , who compares manual anthropometric measurements to the same dimensions extracted from 3D scan. The two sets of measurements are nearly identical.

In conclusion, body sway does occur in Cyberwere whole-body scanning. The displacement of body sway is limited and doesn't affect anthropometric measurement significantly.

5.1 Personally Communicate with Robert Beecher, who works in US Army Natick RD&E Center. 52 CHAPTER SIX

CONCLUSION AND FUTURE RESEARCH

Since the introduction of a commercial laser-based whole-body scanner

(Cyberware WB4), surface digitizing and measurement of the human body has become possible. The system is being used in several areas, such as anthropometric data collection, human engineering, and system modeling. Understanding data accuracy and reliability are fundamental to these applications.

The effects of body movement on scan quality and overall data accuracy are quite significant. In Chapter Three, a method to analyze body movement in scanning is developed and its validity has been proven. To determine the magnitude of the subject's movement, a subject with the cylinder attached was scanned five times. Although the scanning time is relatively short, the subject does move during the scan. From the five scans, the results show that side/side sway is indistinguishable from scan noise, unless the movement is deliberate. A low level of the front/back sway is indicated. Daanen et al. [9] reported similar findings based on a study of subject movement while using the

Cyberware WB4 system at Wright-Patterson Air Force Base (Dayton, Ohio).

One of the first commercial uses for whole-body scanning is custom apparel design. Researchers in the U.S. Army Natick RD&E Center are exploring the whole-body scanning system as an alternative to tailoring. One of their main concerns is apparel measurement error due to body sway in scanning. In Chapter Four, a program 'jackmove' was developed based on JACK software package to solve this problem. 53 JACK is a powerful human factor design and ergonomics visualization

software package. The program 'jackmove' was developed with JACK's CIC++ interface

and Lisp interface. With 'jackmove', the anthropometric measurement errors from body

sway can be analyzed. The results in Table 2 in Chapter Five show that body movement in scanning will not cause significant apparel measurement errors if the body movement is not intentional.

To further investigate the characteristics of body sway in scanning in future, a large survey (for example, 40 males and 40 females) will be needed. Cyberware whole body scanner will scan each subject, fitted with a cylinder. The data from each subject scan will be analyzed using the methods in Chapter Three. The results from this large survey will quantify the amount of human body movement over a scan period. 54 BIBLIOGRAPHY

[1] VIERORDT, K. "Grundriss der Physiologie des Menschen," Tubingen: H.

Lauppschen, 1862.

[2] VLADTh1IR KONCEK, VIKTOR A. POLLAK & ALEXANDER M.YU. "Analysis

of Stability of Human Upright Posture Based Upon the Measurement of the Head

Sway", Medical Progress through Technology, 19: 55-60, 1993.

[3] D. J. THOMAS and r. J. WHITNEY, "Postural Movements During Normal Standing

in Man", The Journal ofAnatomy, Vol. 93, Part 4, 1959.

[4] SI-llMBA T., "An Estimation of Center of Gravity from Force Platform Data,"

J. Biomech., 1984,12:177-182.

[5] G. F. HARRIS, S. A. RIEDEL and D. V. MATESI, "Postural Stability: Frequency

Domain Consideration", IEEElNinth Annual Conference ofthe Engineering in

Medicine and Biology Society, 1987.

[6] H. J. WOLTRING, "New Possibilities for Human Motion Studies by a Real Time

Light Spot Position Measurement," Biotelemetry, Vol. 1, pp.132-146, 1974.

[7] T. LEO and V. MARCELLARI, "On Line Microcomputer System for Gait Analysis

Data Acquisition, Based on Commercially Available Optoelectronic Devices,"

Biomechanics Vol. 7, Baltimore, MD: University of Park Press, 1979.

[8] F. GIANCARLO and P. ANTONION, "ELITE, A Digital Dedicated Hardware

System for Movement Analysis Via Real-Time TV Signal Processing," IEEE

Transaction On Biomedical Engineering, Vol. BME 32, No. 11, 1985. 55 [9] DAANEN, H.A.M., BRUNSMAN, M.A., ROBINETTE, K.M., "Reducing

Movement Artifacts in Whole Body Scanning," IEEE 1997,262-265.

[10] Jack® User's Guide Addendum, Version 5.9, Center for Human Modeling and

Simulation, University of Pennsylvania. 56 Appendix Lx C Programs for Chapter Three

Appendix 1.0 ._.-_. measure.h /**********************************************************************/ /* Head File */ /* Author: Anmin Hu Date: August, 1999 */ /*********************************************************************/ #include #include #include #include

#define TRUE 1 #define FALSE 0 #define FRONT 1 #define BACK 0 #define HALF struct point3D{ float x; float y; float z; }; typedef struct point3D point3d; extern int totalnum, line, position; int plyLoad(FILE *, point3d ** ,int *); void dataSortbyZ(); void dataStatistic(); void cutoff(); void dataAnalysis(); void calculate(); 57 Appendix 1.1 -_._.- measure.c 1**********************************************************************/ 1* Description: This is main program. */ 1* Author: Anmin Hu Date: August, 1999 */ 1**********************************************************************/ #include "measure.h" int totalnum, position; void maine int argc, char *argv[]) { int z,number; point3d *bodypoints; FILE *infile, *outfile; if(argc != 3){ printf("Usage: %s -f (or -b) filename\n",argv[O]); exit(l); } 1* attach the cylinder to body in front or back */ if(strcmp(argv[l],"-f')==O) position=FRONT; else if(strcmp(argv[l],"-b")==O) position=BACK; else { printf("Usage: %s -f (or -b) filename\n",argv[O]); exit(l); } infile=fopen(argv[2],"r"); if(infile==NULL){ printf("can't open '%s\n",argv[2]); exit(l); } outfile=fopen("orig.ascii","w"); if(outfile==NULL){ printf("Can't open file 'orig.ascii\n"); exit(l); } system("clear"); plyLoad(infile,&bodypoints,&number); totalnurnenumber; /* printf("*** 3d coordinats of cylinder data ***\n"); */ for(int i=O; i

Appendix 1.2 •.•.•• plyLoad.c /**********************************************************************/ /* Description: This program implements file conversion from *.ply -> ascii file. */ /* Author: Anmin Hu Date: August, 1999 */ /**********************************************************************/ #include "measure.h"

/* plyLoad -- convert *.ply file to ascii file. */ int plyLoad( FILE *bodyfile, /* *.ply file name */ point3d **body_points,/* big point array to store the point */ int *size) /* total number of point */{ float xyz; float convert_factor =1.0; char rgb; point3d *lbody_points; int i,lsize,no_color =FALSE; int confidence =FALSE; int *lred, *lblue, *lgreen; char line[80], blank[80]; fgets(line, sizeof(line), bodyfile); if(strstr(line,"ply") == NULL) { printf("corrupted data file::ply not found!\n"); retum(FALSE); } fgets(line, sizeof(line), bodyfile); if(strstr(line,"format") == NULL) { printf("corrupted data file::format not found!\n"); retum(FALSE); } fgets(line, sizeof(line), bodyfile); if(strstr(line,"comment") == NULL) { printf("corrupted data file::creation comment not found!\n"); retum(FALSE); } if «strstr(line,"cypie v1.S") != NULL)II(strstr(line,"cyeat") != NULL») convert_factor = 1000.0; if «strstr(line,"cypie v2.3") != NULL»II(strstr(line,"cyopt") != NULL» convert_factor = 1000.0; fgets(line, sizeof(line), bodyfile); sscanf(line, "%s %s %i", blank, blank, &lsize); printf("\nTotal Number of Data Points: %i\n", lsize); if «strstr(line,"element vertex") == NULL)II(lsize < 0») { printf("corrupted data file::element vertex not found!\n"); return(FALSE); } fgets(line, sizeof(line), bodyfile); if(strstr(line,"float") == NULL) { printf("Program version cannot handle data property type!\n"); retum(FALSE); } fgets(line, sizeof(line), bodyfile); if(strstr(line,"float") == NULL) { printf("Program version cannot handle data property typelm"); retum(FALSE); 59 fgets(line, sizeof(line), bodyfile); if(strstr(line,"float") == NULL) { printf("Program version cannot handle data property type!\n"); retum(FALSE); } fgets(line, sizeof(line), bodyfile); if(strstr(Iine,"float") != NULL) { confidence = TRUE; fgets(line, sizeof(line), bodyfile); } if(strstr(Iine,"element") != NULL) {printf("No color data!\n"); no_color = TRUE; } else { if(strstr(line,"uchar") == NULL) { printf("Program version cannot handle data property type!\n"); return(FALSE); } fgets(line, sizeof(line), bodyfile); if(strstr(line,"uchar") == NULL) { printf("Program version cannot handle data property type!\n"); retum(FALSE); } fgets(line, sizeof(line), bodyfile); if(strstr(line,"uchar") == NULL) { printf("Program version cannot handle data property type!\n"); retum(FALSE);

} while (strstr(line, "end_header") == NULL) { if(fgets(line, sizeof(line), bodyfile) == NULL) { printf("corrupted data file::end of header not found!\n"); return(FALSE); } } lbody_points = (point3d *)malloc(sizeof(point3d)*lsize); if(lbody_points == NULL){ printf("Out of memory!"); exit(O); } if (no_color == FALSE) { Ired = (int *)malloc(sizeof(int)*lsize); lgreen = (int *)malloc(sizeof(int)*lsize); lblue = (int *)malloc(sizeof(int)*lsize); if «Ired == NULL)llClblue == NULL)II(lgreen == NULL» { printf("Out of memory!"); exit(O);

} for (i = 0; i < Isize; i++) { fread(&xyz, 1, sizeof(float), bodyfile); lbody_points[i].x = xyz*convert_factor; fread(&xyz, 1, sizeof(float), bodyfile); lbody_points[i].y = xyz*convert_factor; fread(&xyz, 1, sizeof(float), bodyfile); lbody_points[i].z = xyz*convert_factor; if (confidence == TRUE) fread(&xyz, 1, sizeof(float), bodyfile); *body_points = lbody_points; *size = lsize; fclose(bodyfile); retum(TRUE); } } 60 Appendix 1.3 •••••• dataSortByZ.c /**********************************************************************/ /* Description: This program implements the data sort by Z coordinates. */ /* Author: Anmin Hu Date: August, 1999 */ /**********************************************************************/ #include #include #include #include #include "measure.h" struct listnode{ float x.y; struct listnode *next;}; struct treenode{ int z: struct listnode *listhead; struct treenode *left; struct treenode *right; }; struct treenode* treeroot=NULL; struct treenode *treetemp; FILE *output; extern int totalnum; void inserttreenode(struct treenode* nodel,struct treenode** node2); void createtreenode(float x,float y, int z); void printtree(struct treenode*);

/* dataSortByZ - Sort data by Z coordinates and output the result to the file 'data.ascii'. */ void dataSortByZ(){ int fdin,i,j,zO,z,pos; float x,y; char *src; struct stat statbuf; /* open the file orig.ascii for reading*/ if«fdin=open("orig.ascii",O_RDONLY»

/* createtreenode - create a tree node for the points with the same z coordinate.*/ void createtreenode( float x, float y, int z) { treetemp=(struct treenode *)malloc(sizeof(struct treenodej); treetemp-c-zez; treetemp->listhead=(struct listnode *)malloc(sizeof(struct listnodej); treetemp-c-listhead-c-xex; treetemp->listhead->y=y; treetemp->listhead->next=NULL; treetemp->left=NULL; treetemp->right=NULL;

/* insettreenode -- create the binary search tree according z coordinate. Each tree node consists of a linked list which store all the points with the same z-coordinate. */ void inserttreenode( struct treenode* nodel, /* tree node which will not be modified */ struct treenode** node2)/* tree node which will be modified */ { if«*node2)==NULL){ (*node2)=nodel; return; } else{ if(nodel->z > (*node2)->z){ if((*node2)->right==NULL){ (*node2)->right=nodel; return; } else inserttreenode(nodel,&«*node2)->right»; } else{ if(nodel->z < (*node2)->z){ if«*node2)->left==NULL){ (*node2)->left=nodel; return; } else inserttreenode(nodel,&«*node2)->left»; }else{ node1->listhead->next=(*node2)->Iisthead; (*node2)->listhead=node1->listhead; }

/* printtree - output the binary search tree to the file data.ascii. */ void printtree( struct treenode* node) /* tree node. first is treeroot, then recursively call */ { struct Iistnode* temp; int pos; if(node!=NULL){ 62 printtree(node->left); for(temp=node->listhead;temp;temp=temp->next) fprintf(output,"%f %f %d,\n" ,temp->x,temp->y.node-c-z); printtree(node->right); 63 Appendix 1.4 •••••• dataStatistic.c /**********************************************************************/ /* Description: This function implements the data analysis of cylinder slice by */ /* slice according to z-plane. */ /* Author: Anmin Hu Date: August, 1999 */ /**********************************************************************/ #include "measure.h" struct node{ /* store the point number for each z-plane */ int z: int count; struct node *next; }; int lineeO: static struct node *head=NULL; void dataStatistic(){ float x.y; int z; static int z_previous; FILE *infile,*outfile; struct node *templ, *temp2; infile=fopen("data.ascii","r"); if(infile==NULL){ printf("Can't open file 'data.ascii \n "); exit(l); } outfile=fopen("data.stat","w''); if(outfile==NULL){ printf("Can't open file 'data.stat\n"); exit(l); } /* initialize the first node */ templ=(struct node*)malloc(sizeof(struct node)); if(temp1==NULL){ printf("memory allocation error!\n"); exit(1); } templ->z=O; templ->count=l; templ->next=NULL; fscanf(infile,"%f %f %d,",&x,&y,&z_previous); while(fscanf(infile,"%f %f %d,",&x,&y,&z)!=EOF) { if(z==z_previous) templ->count++; else{ temp l->z=z_previous; if(head==NULL){ /* first node */ head=templ ; temp2=temp1; } else{ /* the following node */ temp2->next=temp1; temp2=temp2->next; } templ=(struct node*)malloc(sizeof(struct node)); if(templ==NULL){ printf("memory allocation error!\n"); exittl); 64 templ->z=O; templ->count=l; templ->next=NULL; z_previous=z; } } /* the last one node */ templ->z=z; temp2->next=templ; for(temp1=head;temp1;temp l=templ-c-next){ line++; fprintf(outfile,"%d %d\n" ,templ->z,templ-c-count); } fclose(infile); fclose(outfile); 65 Appendix 1.5 ------cutoff.c /*********************************************************************/ /* Description: This program is for discarding half part of cylinder points which */ /* are close to human body. */ /* Author: Anmin Hu Date: August, 1999 */ /*********************************************************************/ #include "measure.h" #define MAX_POINT 200 float average(int num, float array[]); void cutoff() { int I, count,length, junk3, pre_pos,cur_pos; float point_x[MAX_POINT]; float junkl,junk2,min,max,aver; FILE *infilel, *infile2,*outfile; infile 1=fopen("data.ascii","r"); infile2=fopen("data.stat","r"); outfile=fopen("cutoff.ascii","w"); if(infilel==NULL II infile2==NULL II outfile==NULL ){ printf("Can't open file \n"); exitt l): } pre_pos=ftell(infilel); while(fscanf(infile2,"%d %d",&junk3 ,&count)!=EOF) { for(i=O;iaver) fprintf(outfile,"%f %f %d,\n",junkl,junk2,junk3);

pre_pos=cur_pos; } fclose(infile1); fclose(infile2); fclose( outfile); } float average(int num,/* the dimension of array */ float array[])/* integer array */{ int I; float ave,sum; sum=array[O]; for(i=1 ;i #include #include "measure.h" struct node{ int z; int count; struct node *next; }; static struct node *head=NULL;

/* dataAnalysis -- Analyze the data points for each z-plane from the file 'cutoff.ascii'. */ void dataAnalysis(){ int i,z; float x.y; static int z_previous; FILE *infile,*outfile; struct node *templ, *temp2; infile=fopen("cutoff.ascii","r"); outfile=fopen("cutoff.stat","w"); if(infile==NULL II outfile==NULL){ printf("Can't open file\n"); exit(I);} /* initialize the first node */ templ=(struct node*)maIloc(sizeof(struct node)); if(templ==NULL){ printf("memory allocation error!\n"); exit(I);} templ->z=O; templ->count=l; templ->next=NULL; fscanf(infile,"%f %f %d,",&x,&y,&z_previous); while(fscanf(infile,"%f %f %d,",&x,&y,&z)!=EOF){ if(z==z_previous) temp 1->count++; eIse{ temp1->z=z_previous; if(head==NULL){ /* first node */ headetempl ; temp2=templ; } else { temp2->next=templ; temp2=temp2->next;} templ=(struct node*)maIloc(sizeof(struct node)); if(templ==NULL) {printf("memory allocation error!\n"); exittl );

templ->z=O; templ->count=l; templ­ >next=NULL;z_previous=z; } } temp 1->z=z; temp2->next=temp1; for(templ=head;templ;templ=templ->next) fprintf(outfile,"%d %d\n",templ->z,templ->count); fclose(infile); fclose(outfile); 67 Appendix 1.7 ------calculate.c /**********************************************************************/ /* Descrition: This program is the intersect point between the circle */ /* and a plane which is perpendicular to x-y plane and passing through the */ /* center of circle. */ /* Author: Anrnin Hu Date: August, 1999 */ /**********************************************************************/ #include #include #include #include "measure.h" #define MAX_CUTPOINT 30 #define MAX_HALF 15 struct Point{ float x; float y; int z: }; struct Node{ struct Point point; struct Node *next; }; struct Node *Nodehead=NULL; static float find_min(int num, float array[]); static float find_max(int num, float array[]); static void find_edge(int, struct Point []);

/* calculate -- computing the intersection points between the circle and the plane which is perpendicular to x-y plane and passing through the centre of circle. */ void calculate() { int count, junk; struct Point point[MAX_CUTPOINT]; struct Node *temp; FILE *infile, *infile2, *outfile; infile1=fopen("cutoff.ascii","r"); if(infile1==NULL){ printf("Can't open file 'cutoff. ascii \n"); exit(1); } infile2=fopen("cutoff.stat","r"); if(infile2==NULL){ printf("Can't open file 'cutoff.stat\n"); exit(l); } outfile=fopen("intersect.ascii ","w"); if(outfile==NULL){ printf("Can't open file 'intersect.ascii\n"); exit(1); } while(fscanf(infile2,"%d %d",&junk,&count)!=EOF){ for(int i=O;inext) 68 fprintf(outfile,"%f %f %d,\n",temp->point.x,temp->point.y, temp->point.z); fclose(infile 1); fclose(infile2); fclose(outfile);

/* find_edge -- compute the intersection points for each z-plane. */ void find_edge( int num, /* dimension of Parray */ struct Point Parray[]) /* points array */ { int pos,temp,numl,num2; float min.max.mid; float array[MAX_CUTPOINT]; struct Point Upoint[MAX_HALF]; struct Point Lpoint[MAX_HALF]; struct Point pointl,point2; struct Node *node; struct Node *trnp_node; if(num<=l) return; for(i=O;i

} temp=abs(Upoint[O].y-mid); pos=O; for(i=l .i-cnum l ;++i){ if(temp>abs(Upoint[i].y-mid)){ temp=abs(Upoint[i].y-mid); pos=i; } } /* the closest point to y=mid plane */ pointl.x=Upoint[pos].x; pointl.y=Upoint[pos].y; pointl.z=Upoint[pos].z; temp=abs(Lpoint[O].y-mid); pos=O; for(i=l ;iabs(Lpoint[i].y-mid)){ temp=abs(Lpoint[i].y-mid); posei;

} /* the second closest point to y=mid plane */ point2.x=Lpoint[pos].x; point2.y=Lpoint[pos].y; point2.z=Lpoint[pos].z: node = (struct Node*)malloc(sizeof(struct Node));

node->point.x=(pointl.x+point2.x)/2; node->point.y=(pointl.y+point2.y)/2; node->point.z=(pointl.z+point2.z)/2; node->next=NULL if(Nodehead==NULL) 69 Nodeheadenode; else{ for(tmp_node=Nodehead;tmp_node->next;tmp_node=tmp_node->next)

tmp_node->next=node;

} /* find_min -- find a minum from a array */ float find_min(int num, /* the dimension of array */ float array[]) /* integer array */ { int i; float min; min=array[O]; for(i=l ;iarray[i]) minearrayji]; retum(min);

/* find_max -- find a maximum from a array */ float find_max(int num,/* the dimension of array */ float array[]) /* integer array */ { int i; float max; max=array[O]; for(i=l ;i

Appendix 2.0 --- capi.h /*********************************************************************/ /* Header file */ /* Author: Anmin Hu Date: August, 1999 */ /*********************************************************************/ #include #include #include #include void adjustJoint(void); void jointmenu(void); void printJointlnfo(JackPtr *jointptr,int); void mainmenu(void); void nodemenu(void); void dataInit(void); void move_center_gravity(void); typedef struct { float x; float y; float z; } Point; extern Point location[LOC_NUM]; extern char node_info[LOC_NUM][MAX_LSTR]; extern int position; extern int first; extern float length_original[LEN_NUM]; extern int figure_reset; void picknewpoint(Point **); void showmovement(Point *,int); void showlengtherror(void); void initial_Iength(void); void shownode(void); 71 Appendix 2.1 •• main.c /**********************************************************************/ /* Descrition: The functionality of this main program is: connect Jack Server */ /* using SUN-RPC, read jack.env file in -/jack directory, display Jack */ /* with stand up posture, setup Jack balance control, and initial the all */ /* location coordinates and length. Then, following the main menu, select */ /* any action. */ /* Author: Anmin Hu Date: August,1999 */ /**********************************************************************/ #include #include #include "capi.h" int position; int first=O; void maine int argc, /* number of argument */ char *argv[]) /* input server domain name */ { char ch; char buf[256]; int i,check; float d,dO,dl,d2; JackFlags flag; char *servemm = argc>l ? argv[l] : NULL; if (!JACKrpc_init(servemm,IOOO,"waiting for connection...\n"» exit(-I); JACKjcl("make_background_shaded(\"jack window\");",TRUE); if((checkedACKjcl("read_file(\"-/jack/jack.en v\");",TRUE))==FALSE){ printf("Error occur in 'JACKjcl()' called\n"); exit(-I); } JACKjcl("make_everythin~shaded(\"jack window\");",TRUE); JACKjcl("set_balance_control(\"jack\",\"hold current position',"); ",TRUE); /* initial all location coordinates */ printf("\n(waiting for initializing the data ...)\n"); for(i=O;i #include #include #include "capi.h" int first_move=O, figure_reset=O; /* move_center_gravity -- input the forward-to-backward and side-to side values and move the center of gravity. */ void move_center_gravity(){ int check; float x,y,z,delta_x,delta_z; char front_part[MAX_STR]={

rr(rawjcl \"move_center_of_mass(\\\"jack\\\",xyz(-91.16deg,2.59deg,-89.87deg) }; char center_of_gravity[MAX_LSTR]; /* reset human body to original posture */ if(first_move==O) first_move=1; else{ /* re-readjack.fig to keep the same posture */ figure_reset=1 ; printf("(waiting for re-read '.Ijack.env' ...)\nff); JACKjcl(ffdelete_figure(\"jack\ff);",TRUE); if((check=JACKjcl("read_file(\"-/jack/jack.env\");",TRUE))==FALSE){ printf("Error occur in 'JACKjcl()' called\n"); exitt-L); } JACKjcl("make_everythin~shaded(\"jack window\");",TRUE); JACKjcl(ffset_balance_control(\"jack\ff,\"hold current position',");" ,TRUE); } /* original center of gravity:trans(-8.50cm,112.37cm,-8.51cm) */ x=-8.50; z=-8.51; /* initalize x and z */ fflush(stdin);fflush(stdout); printf("Enter the movement value in side-to-sidetcm):"); scanf(ff%f',&delta_x); printf("Enter the movement value in back-to-forth/em):"); scanf(ff%f',&delta_z); x+=delta_x ;z+=delta_z; sprintf(center_of~ravity,ff%s%fcm,112.37cm,%fcm»;\ff)ff,front_part,x,z); if (JACKlisp(center_of_gravity,center_of_gravity,MAX_LSTR» printf("\nCall movecenterofgravitytj.retum %s\n\n ff ,center_of_gravity); else printf("%s: LISP ERROR\n".centerof'gravity); shownode(); 73

Appendix 2.3- adjust.loint.c /**********************************************************************/ /* Description: This program is for adjusting the human body joints and finding */ /* out how much effects on other parts. The joints we are interested in are */ /* ELBOW, SHOULDER, HIP, KNEE, NECK, AND WAIST. */ /* Author: Anmin Hu Date: August, 1999 */ /**********************************************************************/ #include #include #include #include #include "capi.h" static int initial[6]={ O,O,O,O,O,O}; /* initialize the each joint angles */ static float angle_reset[6][3]; /* reset the angles */ extern int first_move; void adjustJoint(){ int check; char ch; char buf[256]; float x.y,z; float angles[3]; JackPtr jackptr; JackPtr jointptr; char center_of_gravity[MAX_LSTR]; char *jointname[6]={ "left_elbow","left_shoulder","left_hip", "left_knee","atlanto_occipital","waist"}; static float initial_angles[6][3];

if(first_move==1){ figure_reset=l; printf("(waiting for re-read './jack.env' ...)\n"); JACKjcl("delete_figure(\"jack\");",TRUE); if«check=JACKjcl("read_file(\"-/jack/j ack.env\");",TRUE))==FALSE){ printf("Error occur in 'JACKjcl()' called\n"); exit(-1); } JACKjcl("make_everythin~shaded(\"j ack window\");",TRUE); JACKjcl("set_balance_control(\"jack\",\"hold current position',");",TRUE); } JACKfigure_find("jack",&jackptr,1); jointmenu(); fflush(stdin); scanf("%c",&ch); while(ch !='r){ switch(ch){ case '0': /* adjust left_elbow */ JACKfigurejointUackptr,jointname[0],&jointptr,1); if(initial[0]==0){ JACKjoint_anglesUointptr,initial_angles[0],3, NOFLAGS); angle_reset[0][O]=initial_angles[O][0]; initial_angles[O][Ol=(initial_angles[O][0]*180/3.14); angles [O]=initial_angles[0][0]; 74 initial[O]=1 ; } else { JACKjoint_angles(jointptr,angles,l, NOFLAGS); angles[O]=(angles[O]* 180/3.14); } printf("\njoint type: R(-y)\n"); printf("current values: %f (deg)\n",angles[O]); printf("Enter new displacement value (deg)?"); scanf("%f',&angles[O]); angles[0]=angles[0]*3.14/180; /* convert to radius */ JACKjoint_angles(jointptr,angles,l, VALUE_SET); break; case '1': /* adjust left_shoulder */ JACKfigurejoint(jackptr,jointname[1],&jointptr,1); if(ini tial [1]==0){ JACKjoint_angles(jointptr,initial_angles[1],3, NOFLAGS); angle_reset[1][O]=initial_angles[1][0]; angle_reset[1][1]=initiai_angles[1][1]; angle_reset[1][2]=initial_angles[1][2]; initial_angles[1][O]=(initial_angles[1][0]* 180/3.14); initial_angles[l][1]=(initial_angles[l][1]* 180/3.14); initial_angles[1][2]=(initiaI_angles[1][2]* 180/3.14); angles[O]=initial_angles[1][0]; angles[1]=initial_angles[1][1]; angles[2]=initial_angles[1][2]; initial[1]=1; } else{ JACKjoint_angles(jointptr,angles,3, NOFLAGS); angles[O]=(angles[O]* 180/3.14); angles[1]=(angles[1]*180/3.14); angles[2]=(angles[2]*180/3.14); } printf("\njoint type: R(z) * R(x) * R(y)\n"); initial_angles[1][0], initial_angles[l][l],initial_angles[1][2]);*/ printf("current values: %f(deg) * %f(deg) * %f(deg)\n", angles[O], angles[I], angles[2]); printf("Enter new displacement value?(deg)"); scanf("%f %f %f",&angles[O],&angles[1],&angles[2]); angles[O]=angles[0]*3.14/ 180; angles[1]=angles[1]*3.14/ 180; angles[2]=angles[2]*3.14/ 180; JACKjoint_angles(jointptr,angles,3, VALUE_SET); break; case 2': /* adjust left hip */ JACKfigurejoint(jackptr,jointname[2],&jointptr,1); if(initial[2]==0){ JACKjoint_angles(jointptr,initial_angles[2],3, NOFLAGS); angle_reset[2][O]=initial_angles[2][0]; 75 angle_reset[2][1]=initial_angles[2][1]; angle_reset[2][2]=initial_angles[2][2]; initial_angles[2][0]=(initial_angles[2][0]* 180/3.14); initial_angles[2][1]=(initial_angles[2][1]* 180/3.14); initial_angles[2][2]=(initial_angles[2][2]* 180/3.14); angles[0]=initial_angles[2][0]; angles[1]=initial_angles[2][1]; angles[2]=initial_angles[2][2]; initial[2]=I; } else{ JACKjoint_anglesUointptr,angles,3, NOFLAGS); angles[O]=(angles[O]* 180/3.14); angles[I]=(angles[I]*180/3.14); angles[2]=(angles[2]*180/3.14); } printf("\njoint type: R(z) * R(x) * R(y)\n"); initial_angles[2][0], initial_angles[2][1],initial_angles[2][2]); *1 printf("current values: %f(deg) * %f(deg) * %f(deg)\n", angles[O], anglesjl], angles[2]); printf("Enter new displacement value?(deg)"); scanf("%f %f %f",&angles[O] ,&angles[1],&angles[2]); angles[O]=angles[O] *3.14/180; angles[1]=angles[1]*3.14/180; angles[2]=angles[2]*3.14/180; JACKjoint_angles(jointptr,angles,3, VALUE_SET); break; case '3': 1* adjust left knee *1 JACKfigure.jointUackptr,jointname[3],&jointptr,I); if(ini tial [3]==0){ JACKjoint_anglesUointptr,initial_angles[0],3, NOFLAGS); angle_reset[3][O]=initial_angles[3][0]; initial_angles[O][0]=(initial_angles[3][0]* 180/3.14); angles[0]=initial_angles[3][0]; initial[3]=I; } else { JACKjoint_anglesUointptr,angles,3, NOFLAGS); angles[Ol=(angles[Ol*180/3.14); } printf("\njoint type: R(-y)\n"); printf("current values: %f (deg)\n",angles[O]); printf("Enter new displacement value (deg)?"); scanf("%f',&angles[O]); angles[Ol=angles[O]*3.14/180; /* convert to radius */ JACKjoint_angles(jointptr,angles,l, VALUE_SET); break; case '4': /* adjust neck */ JACKfigure.jointUackptr,jointname[4],&jointptr,1); if(initial[4]==O){ JACKjoint_anglesUointptr,initial_angles[4],3, NOFLAGS); angle_reset[4] [Ol=initial_angles[4] [0]; 76 angle_reset[4] [1]=initial_angles[4][1]; angle_reset[4] [2]=initial_angles[4] [2]; initial_angles[4][0]=(initial_angles[4][0]* 180/3.14); initial_angles[4][ 1]=(initial_angles[4] [1]* 180/3.14); initial_angles[4][2]=(initial_angles[4][2]*180/3.14); angles[O]=initial_angles[4][0]; angles[1]=initial_angles[4][1]; angles[2]=initial_angles[4][2]; initial[4]=1; } else{ JACKjoint_angles(jointptr,angles,3, NOFLAGS); angles[O]=(angles[O]* 180/3.14); angles[1]=(angles[I]*180/3.14); angles[2]=(angles[2]*180/3.14); } printf("\njoint type: R(z) * R(x) * R(y)\n"); initial_angles[4][0], initial_angles[4][1],initial_angles[4] [2]);*/ printf("current values: %f(deg) * %f(deg) * %f(deg)\n", angles[O], angles[I], angles[2]); printf("Enter new displacement value?(deg)"); scanf("%f %f %f',&angles[0],&angles[I],&angles[2]); angles[0]=angles[0]*3.14/180; angles[I]=angles[1]*3.14/180; angles[2]=angles[2]*3.14/180; JACKjoint_angles(jointptr,angles,3, VALUE_SET); break; case '5': /* adjust waist */ JACKfigurejoint(jackptr,jointname[5],&jointptr,I); if(initial[5]==0){ JACKjoint_angles(jointptr,initial_angles[5],3, NOFLAGS); angle_reset[5][0]=initial_angles[5][0]; angle_reset[5][1]=initial_angles[5][1]; angle_reset[5][2]=ini tial_angles[5][2]; initial_angles[5][0]=(initial_angles[5][0]* 180/3.14); initial_angles[5][1]=(initial_angles[5][1]* 180/3.14); initial_angles[5][2]=(initial_angles[5][2]* 180/3.14); angles[0]=initial_angles[5][0]; angles[1]=initial_angles[5][1]; angles[2]=initial_angles[5][2]; initial[5]=I; }else{ JACKjoint_angles(jointptr,angles,3, NOFLAGS); angles[O]=(angles[O]*180/3.14); angles[I]=(angles[1]*180/3.14); angles[2]=(angles[2]*180/3.14); } printf("\njoint type: R(z) * R(x) * R(y)\n"); initial_angles[5][0], initial_angles[5][1],initial_angles[5][2]); */ printf("current values: %f(deg) * %f(deg) * %f(deg)\n", angles[O], angles[I], angles[2]); printf("Enter new displacement value?(deg)"); scanf("%f %f %f',&angles[O],&angles[1],&angles[2]); 77 angles[O]=angles[O]*3.14/180; angles[ 1]=angles[1]*3.14/180; angles[2]=angles[2]*3.14/180; JACKjoint_anglesUointptr,angles,3, VALUE_SET); break; default: break; }; shownode(); /* reset the previous adjustment */ switch(ch){ case '()': JACKjoint_anglesUointptr,angle_reset[O],I, VALUE_SET); break; case '1': JACKjoint_anglesUointptr,angle_reset[I],3, VALUE_SET); break; case '2': JACKjoint_anglesUointptr,angle_reset[2],3, VALUE_SET); break; case 3': JACKjoint_anglesUointptr,angle_reset[3],I, VALUE_SET); break; case '4': JACKjoint_anglesUointptr,angle_reset[4],3, VALUE_SET); break; case '5': JACKjoint_anglesUointptr,angle_reset[5],3, VALUE_SET); break; default: break; }; jointmenu(); fflush(stdin); scanf("%c",&ch); 78 Appendix 2.4 ._- datalnit.c /**********************************************************************/ /* Description: Initialize the coordinates for all locations which are chosen. */ /* Author: Anmin Hu Date: August, 1999 */ /**********************************************************************/ #include "capi.h" Point Iocation[LOC_NUM]; char node_info[LOC_NUM][MAX_LSTR]={ "(rawjcl \"node_info(\\\"jack.left_lower_arm.l36\\\");\")",/*wrist*/ "(rawjcl \"node_info(\\\"jack.left_lower_arm.29\\\");\")", /*elbow*/ "(rawjcl \"node_info(\\\"jack.lower_torso.579\\\");\")", /*shoulder*/ "(rawjcl \"node_info(\\\"jack.bottom_head.l41\\\");\")", /* head */ "(rawjcI \"node_info(\\\"jack.lower_torso.461\\\");\")", /* chest */ "(rawjcl \"node_info(\\\"jack.lower_torso.292\\\");\")", /* abdomen */ "(rawjcl \"node_info(\\\"jack.left_upper_leg.23\\\");\")", /* upper leg */ "(rawjcl \"node_info(\\\"jack.left_lower_leg.72\\\");\")", /* lower leg */ "(rawjcl \"node_info(\\\"jack.left_upper_leg.15\\\");\")", /* left inseam */ "(rawjcl \"node_info(\\\"jack.lower_torso.232\\\");\")", /* left outseam */ "(rawjcl \"node_info(\\\"j.ack.cerv7.94\\\");\")", /* neck */ "(rawjcl \"node_info(\\\"jack.left_foot.86\\\");\")", /* left foot_inner */ "(rawjcl \"node_info(\\\"jack.left_foot.87\\\");\")" /* left foot_outer */ }; void dataInit(){ float x.y.z; static int count=O; char line[MAX_ARRAY]; char *ptr; system("cp ../.jack.log ./temp.Iog"); FILE *infile=fopen("temp.log","r"); if(infile==NULL){ printf("can't open ../temp.Iog file\n"); exit(O);} if(first==O){ for(int i=O;i<66;++i) fgets(line,MAX_ARRAY,infile); fgets(line,MAX_ARRAY,infile); if«ptr=strchr(line,'()!=NULL){ sscanf(ptr,"(%f,%f,%f)",&x,&y,&z); location[count].x=x; location[count].y=y; location[count].z=z; count++; } position=ftell(infile); firste l; } else{ fseek(infile,position,SEEK_SET); for(i=O;i<6;++i) fgets(line,MAX_ARRAY,infile); fgets(line,MAX_ARRAY,infile); if«ptr=strchr(line,'()!=NULL){ /* search for coordinates */ sscanf(ptr,"(%f,%f,%f)",&x,&y,&z); location[count].x=x; ocation[count].y=y; location[count].z=z; count++; } position=ftell(infile); /* keep a file position */ } fclose(infile); 79 Appendix 2.5 ••• initiaI_length.c /**********************************************************************/ /* Description: calculate all initial length before body movement. */ /* Author: Anmin Hu Date: August, 1999 */ /**********************************************************************/ #include #include "capi.h" float length_original[LEN_NUM]; /* store initial length value */

/* * initial_length -- calculate all initial length before moving */ void initial_Iength() { float d,dO,dI,d2;

dO=location[2].x-location[O].x; d1=location[2].y-Iocation[0].y; d2=location[2].z-location[0].z; length_original[O]=sqrt(dO*dO+d1*dl+d2*d2); /* sleeve inseam */

dO=location[8].x-location[ II].x; dl=location[8].y-location[II].y; d2=location[8].z-location[11].z: length_original[I]=sqrt(dO*dO+dI *dl+d2*d2); /* leg inseam */

dO=location [9].x-location[12].x; dl=location[9].y-Iocation[12].y; d2=location[9].z-location[12].z; length_original[2]=sqrt(dO*dO+d1*dl+d2*d2); /* leg outseam */

length_original[3]=location[5].y; /* waist height */

length_original[4]=location[2].y;/* shoulder height */

length_original[5]=location[10].y; /* neck height */

length_original[6]=location[3].y;/* stature height */ 80 Appendix 2.6 --- picknewpoint.c /**********************************************************************/ /* Description: pick up the new coordinate for the location after movement */ /* Author: Anmin Hu Date: August, 1999 */ /**********************************************************************/ #include #include #include #include "capi.h" void picknewpoint( Point **point) /* new location coordinate after a moving */ { int tmp, count; float x,y,z; char line[MAX_ARRAY]; char *ptr; Point *temp; system("cp ../.jack.log ./temp.log"); FILE *infile = fopen("temp.log","r"); if(infile==NULL){ printf("can't open ../.jack.log file\n"); exit(O); } temp=(Point *)malloc(sizeof(Point)); fseek(infile,position,SEEK_SET); if(figure_reset==O){ for(int i=O;i<6;++i) fgets(line,MAX_ARRAY.infile); fgets(line,MAX_ARRAY.infile); } else{ for(i=O;i<58;++i) /* jump over the line due to read ./jack.env */ fgets(line,MAX_ARRAY,infile); fgets(line,MAX_ARRAY.infile); figure_reset=O; } if((ptr=strchr(line,r»!=NULL){ sscanf(ptr,"(%f,%f, %f)" ,&x,&y,&z); temp-c-xex.temp-c-yey.temp-c-zez; } position=ftell(infile); (*point)=temp; fclose(infile); 81 Appendix 2.7 ••• showmovement.c /**********************************************************************/ /* Description: calculate the movement between the new location and the */ /* original location. */ /* Author: Anmin Hu Date: August,1999 */ /**********************************************************************/ #include #include "capi.h"

/* * showmovement -- compute how much movement bewteen the new * location and original location. */ void showmovement( Point *point, /* location after moving */ int index) /* index to choose */

float d,dO,dl,d2;

#ifndef DEBUG system("clear"); #endif

dO=point->x-location[index].x; d1=point-c-y-location[index].y; d2=point-c-z-Iocation[index] .z; d=sqrt(dO*dO+dl *dl+d2*d2);

printf("\n\n------\n"); printf("- MEASUREMENT RESULTS -\n"); printf(" ------\n\n");

printf("Displacement in x-direction: %f(cm)\n",dO); printf("Displacement in y-direction: %f(cm)\n",dl); printf("Displacement in z-direction: %f(cm)\n",d2); printf("MOVEMENT %f (em) OCCUR!\n\n\n",d); 82 Appendix 2.8 --- showlengtherror.c /**********************************************************************/ /* Description: calculate the measurement error bewteen the new length and */ /* the original length. */ /* Author: Anmin Hu Date: August,1999 */ /**********************************************************************/ #include #include "capi.h" void showlengtherror() { float d,dO,dl ,d2,lengtherror; Point *point; char buf[256]; printf("\n\n------\n"); printf("- MEASUREMENT RESULTS -\n"); printf(" ------\n\n"); /* SLEEVE INSEAM */ strcpy(buf,node_info[O]); if (JACKlisp(buf,buf,MAX_LSTR» printf("\t%s: LISP ERROR\n",but); picknewpoint(&point); dO=point->x-location[2].x; dl=point->y-Iocation[2].y; d2=point->z-location[2].z; d=sqrt(dO*dO+dl*dl+d2*d2); lengtherror=d-Iength_original[0]; printf("SLEEVE INSEAM ERROR: %f(cm)\n",lengtherror); /* LEG INSEAM error */ strcpy(buf,node_info[8]); if (JACKlisp(buf,buf,MAX_LSTR» printf("\t%s: LISP ERROR\n",but); picknewpoint(&point); dO=point->x-location[ll].x; dl=point->y-Iocation[ll].y; d2=point->z-location[11].z; d=sqrt(dO*dO+dl*dl+d2*d2); lengtherror=d-Iength_original[1]; printf("LEG INSEAM ERROR: %f(cm)\n",lengtherror); /* LEG OUTSEAM */ strcpy(buf,node_info[9]); if (JACKlisp(buf,buf,MAX_LSTR» printf("\t%s: LISP ERROR\n",buf); picknewpoint(&point); /* get a location after moving */ dO=point->x-location[12].x; dl=point->y-Iocation[12].y; d2=point->z-location[12].z; d=sqrt(dO*dO+dl *dl+d2*d2); lengtherror=d-Iength_original[2]; printf("LEG OUTSEAM ERROR: %f(cm)\n",lengtherror); /* WAIST HEIGHT */ strcpy(buf,node_info[5]); if (JACKlisp(buf,buf,MAX_LSTR» printf("\t%s: LISP ERROR\n",buf); 83 picknewpoint(&point); /* get a location after moving */ d=point->y; lengtherror=d-length_originaI[3]; printf("WAIST HEIGHT ERROR: %f(cm)\n",Iengtherror); /* SHOULDER HEIGHT */ strcpy(buf,node_info [2]); if (JACKlisp(buf,buf,MAX_LSTR» printf("\t%s: LISP ERROR\n",but); picknewpoint(&point); /* get a location after moving */ d=point->y;lengtherror=d-Iength_original[4]; printf("SHOULDER HEIGHT ERROR: %f(cm)\n",lengtherror); /* NECK HEIGHT */ strcpy(buf,node_info[10]); if (JACKlisp(buf,buf,MAX_LSTR» printf("\t%s: LISP ERROR\n",but); picknewpoint(&point); /* get a location after moving */ depoint-c-y; lengtherror=d-Iength_original[5]; printf("NECK HEIGHT ERROR: %f(cm)\n",Iengtherror); /* STATURE HEIGHT */ strcpy(buf,node_info[3]); if (JACKlisp(buf,buf,MAX_LSTR» printf("\t%s: LISP ERROR\n".buf); picknewpoint(&point); /* get a location after moving */ d=point->y; lengtherror=d-length_originaI[6]; printf("STATURE HEIGHT ERROR: %f(cm)\n",lengtherror); 84 Appendix 2.9 _•• shownode.c /**********************************************************************/ /* Description: show the location and length which will be chosen. */ /* Author: Anmin Hu Date: August, 1999 */ /**********************************************************************/ #include "capi.h" void shownode() { int index,flag=O; char ch; Point *point; char buf[256]; nodemenu(); fflush(stdin); scanf("%d",&index); while(index!=10){ if(index==8){ showlengtherror(); } else{ strcpy(buf,node_info[index]); if (JACKlisp(buf,buf,MAX_LSTR» printf("Call node_info(%s), retum%s\n",node_info[index],buf); else printf("\t%s: LISP ERROR\n",buf); picknewpoint(&point); /* get a location after moving */ #ifdef DEBUG printf("original point: x=%f, y=%f, z=%t\n",location[index].x, location[index].y,location[index].z); printf("new point: x=%f, y=%f, z=%t\n",point->x,point->y, point-c-z); #endif #ifndef DEBUG system("clear"); #endif

showmovement(point,index); } nodemenu(); fflush(stdin); scanf("%d",&index); 85 Appendix 2.10 ••• mainmenu.c /**********************************************************************/ /* Description: display main menu. */ /* Author: Anmin Hu Date: August,1999 */ /**********************************************************************/ #include #include #include void mainmenu(void) { printf("ill\n------ill"); printf(" - -\n"); printf("- HUMAN BODY MOVEMENT ANALYSIS PROGRAM -xn''); printf("- -\nil); printf(" ------\n\n\n");

printf("\tO:\tMOVE CENTER OF GRAVITY\n"); printf("\tl:\tMOVE HUMAN BODY PARTS\n");

printf("ill\n\tq:\tQUI1\n");

for(int i=O;i<5;++i) printf("\n\n ");

printf("ENTER YOUR SELECTION?");

fflushtstdout); 86 Appendix 2.11 •••jointmenu.c /**********************************************************************/ /* Description: display joint name which you want to select. */ /* Author: Anmin Hu Date: August,1999 */ /**********************************************************************/

#include #include #include void jointmenu(void) { printf("\n\n"); printf("**************************************************\n"); printf("* *\n"); printf("* MENU FOR ADJUST BODY JOINTS *\n"); printf("* *\n"); printf("**************************************************\n\n\n");

printf("\tO:\tAdjust LEFT_ELBOW\n"); printf("\tl:\tAdjust LEFT_SHOULDER\n"); printf("\t2:\tAdjust LEFT_HIP\n"); printf("\t3:\tAdjust LEFT_KNEE\n"); printf("\t4:\tAdjust NECK\n"); printf("\t5:\tAdjust WAIST\n");

printf("\n\n\tr:\tRetum previous menu\n");

for(i=O;i<5;++i) printf("\n\n");

printf("Enter your selection?"); 87 Appendix 2.12 --- nodemenu.c /**********************************************************************/ /* Description: display location and length you want to select. */ /* Author: Anmin Hu Date: August,1999 */ /**********************************************************************/

#include #include #include void nodemenu{void) { printf("\n\n"); printf{"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\n"); printf("$$ $$\n"); printf{"$$ PICK THE FOLLOWING ITEM YOU ARE INTERESTED IN $$\n"); printf("$$ $$\n");

printf{"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\n\n\n")

printf{"\tO:\tSelect LEFf WRIST\n"); printf{"\tl:\tSelect LEFf ELBOW\n"); printf{"\t2:\tSelect LEFf SHOULDER\n"); printf{"\t3:\tSelect HEAD\n"); printf{"\t4:\tSelect CHEST\n"); printf{"\t5:\tSelect ABDOMAN\n"); printf{"\t6:\tSelect LEFf UPPER LEG\n"); printf{"\t7:\tSelect LEFf LOWER LEG\n");

printf{"\n\t8:\tAPPAREL error?\n");

printf{"\n\n\tIO:\tRetum previous menu\n");

for{i=O;i<5;++i) printf("\n");

printf{"Enter your selection ?");