/* * Katie Lewis * April 2004 * Note: In codeing this referred to code examples from Professor Kuenning * and Matt Gnaizda. */ #include "plant.hh" #include #include #include #include #include "plantiterator.hh" #include "location.hh" #include "node.hh" const int START_SIZE_ = 10; using namespace std; const int MutateVariance = 20; /* Plant Null Constructor */ Plant::Plant() : root(NULL), suntype(SUN_DEFAULT), shape(SHAPE_DEFAULT), leafFunction(L_FUNC_DEFAULT), structFunction(S_FUNC_DEFAULT), minBranching(MIN_BING_DEFAULT), maxBranching(MAX_BING_DEFAULT) { } /* Plant Destructor */ Plant::~Plant() { deleteAll(root); } Plant::Plant(Sun sun_, LeafShape shape_, LeafFunction lf_, StructFunction sf_, int mb, int mxb) : root(NULL), suntype(sun_), shape(shape_), leafFunction(lf_), structFunction(sf_), minBranching(mb), maxBranching(mxb) { } /* Plant Assignment Operator */ Plant& Plant::operator=(const Plant& i) { suntype = i.suntype; shape = i.shape; leafFunction = i.leafFunction; structFunction = i.structFunction; minBranching = i.minBranching; maxBranching = i.maxBranching; root = copy(i.root); return *this; } /* Copy Constructor */ Plant::Plant(const Plant& i) : suntype(i.suntype), shape(i.shape), leafFunction(i.leafFunction), structFunction(i.structFunction), minBranching(i.minBranching), maxBranching(i.maxBranching) { root = copy(i.root); } bool Plant::addBranchPoint(const Location& placetoadd, const Location& tobeadded) { Node* toBeAdded = new Node(tobeadded); Node* placeToAdd = findLoc(root, placetoadd); return add(placeToAdd, toBeAdded); } bool Plant::addLeaf(const Location& placetoadd) { Node* toBeAdded = new Node(true); Node* placeToAdd = findLoc(root, placetoadd); return add(placeToAdd, toBeAdded); } bool Plant::addBetween(const Location& parent, const Location& tobeadded, Location& child) { Node* toBeAdded = new Node(tobeadded); Node* placeToAdd = findLoc(root, parent); return addBetween(placeToAdd, toBeAdded, child); } bool Plant::randomAddBranchPoint() { return randomAdd(createRandomNode(false)); } bool Plant::randomAddLeaf() { return randomAdd(createRandomNode(true)); } void Plant::randomAddAnywhere() { cout << "Entering randomAddAnywhere " << endl; randomAddAnywhere(createRandomNode(false)); } double Plant::findFitness() { return structCost() - leafBenefit(); } Plant& Plant::cross(Plant& B) { Plant* X = new Plant(*this); Node* a = X->selectRandomNode(); int place = rand()%(a->numLinks); Node* b = B.selectRandomNode(); deleteAll(a->links[place]); a->links[place] = copy(b); return *X; } Plant& Plant::mutate1() { Plant* X = new Plant(*this); Node* victim = X->selectRandomNode(); int sign = 1; if (rand()%2 ==1) sign=-1; victim->loc.x = victim->loc.x + (sign)*rand()%MutateVariance; if (rand()%2 ==1) sign=-1; victim->loc.y = victim->loc.y + (sign)*rand()%MutateVariance; return *X; } void Plant::printPovray() { /* Includeds */ cout << "#include \"colors.inc\" " << endl << endl << "#version 3.5; \n" << endl << endl; cout << "global_settings { \n \t assumed_gamma 1.0 \n } " << endl << endl; /* Camera */ cout << "camera { location < 0, -5, 4 >" << endl; cout << "look_at <0,2, 4>" << endl; cout << "}" << endl << endl; /* Light Sources */ cout << "light_source { \n" << "\t 0*x \n" // light's position (translated below) << "\t color rgb <1,1,1> \n" << "\t spotlight \n" << "\t translate <40, 80, -10> \n" // position of light << "\t point_at <0, 0, 0> \n" // direction of spotlight << "\t radius 5 \n" // hotspot (inner, in degrees) << "\t tightness 30 \n" // tightness of falloff (1...100) low:softer << "\t falloff 8 \n" // intensity falloff radius (outer, in degrees) << "}" << endl << endl; /* Plant */ printPov(root); /* Statistics */ } void Plant::printStatistics() { string sunTypE = "huh"; string leafShapE = "huh"; string leafFunctionE = "huh"; string structFunctionE = "huh"; if (suntype == DOWN) sunTypE = "down"; if (shape == EASY) leafShapE = "easy"; if (leafFunction == A) leafFunctionE = "A"; if (structFunction == X) structFunctionE = "X"; cout << "Stats: " << endl << "Plant Fitness: " << findFitness() << endl << "Total number of Branch points: " << endl << "Total number of leaves: " << endl << "Sun Type: " << sunTypE << endl << "Leaf Shape: " << leafShapE << endl << "Leaf Function: " << leafFunctionE << endl << "Plant Structure Function: " << structFunctionE << endl << "Min Number of Branches per branch point: " << minBranching << endl << "Max Number of Branches per branch point: " << maxBranching << endl; } void Plant::printRawBranchPointLocations() { } /* Private Functions ******************************************************/ bool Plant::add(Node* placetoadd, Node* tobeadded) { return placetoadd->add(tobeadded, maxBranching); } bool Plant::addBetween(Node* placetoadd, Node* tobeadded, Location& child) { return placetoadd->addBetween(tobeadded, child, maxBranching); } Node* Plant::selectRandomNode() { if (root == NULL) return root; int place = rand()%nodeCount(root); PlantIterator i(root); for (int j = 0; j < place; ++j) { ++i; } return i.current; } Node* Plant::createRandomNode(bool isLeaf) { if (isLeaf) { Node* l = new Node(true); return l; } else { int sign1 = 1; if (rand()%2 ==1) sign1=-1; int sign2 = 1; if (rand()%2 ==1) sign2=-1; Node* n = new Node(Location((sign1)*((rand()%(MutateVariance*1000))/1000.0), (sign2)*((rand()%(MutateVariance*1000))/1000.0), ((rand()%(MutateVariance*1000))/1000.0))); return n; } } bool Plant::randomAdd(Node* tobeadded) { int place = rand()%nodeCount(root); PlantIterator i(root); for (int j = 0; j < place; ++j) { ++i; } for (int j = 0; j < i.current->sizeLinksArray; ++j) { if (i.current->links[i] != NULL) { i.current->links[i] = tobeadded; ++(i.current->numLinks); return true; } } return false; } void Plant::randomAddAnywhere(Node* input) { assert(input != NULL); // can't add a nonexistent node cout << "Enter randomAddAnywhere2 " << endl; if (root == NULL) { root = input; return; } int k = nodeCount(root); cout << "nodeCount(root) " << k << endl; PlantIterator i(root); cout << "Iterator set " << endl; if (k > 0) { int place = rand()%k; cout << "place is " << place << endl; for (int j = 0; j < place; ++j) { ++i; } } cout << "iterator set " << endl; cout << "i.current->sizeLinksArray - i.current->numLinks " << i.current->sizeLinksArray - i.current->numLinks << endl; if (i.current->links == NULL) { int newSize; if (START_SIZE_ > maxBranching) newSize = maxBranching; else newSize = START_SIZE_; i.current->links = new Node*[newSize]; for (int n = 0; n < newSize; ++n) i.current->links[n] = NULL; add(i.current, input); } int place2 = rand()%(i.current->sizeLinksArray - i.current->numLinks); cout << "++iterset " << endl; if (i.current->links[place2]->isLeaf) add(i.current, input); else addBetween(i.current, input, i.current->links[place2]->loc); cout << "Exit randomAddAnywhere " << endl; } /* Helper function to Copy Constructor and Assignment Operator */ Node* Plant::copy(Node* input) { Node* newNode = new Node(*input); for (int i = 0; i < newNode->sizeLinksArray; ++i) { if (newNode->links[i] != NULL) newNode->links[i] = copy(newNode->links[i]); } return newNode; } void Plant::deleteAll(Node* input) { if (input == NULL) return; for (int i = 0; i < input->sizeLinksArray; ++i) { if (input->links[i] != NULL) { deleteAll(input->links[i]); delete input->links[i]; } } delete input; } /* * Here is the current node we're checking. Null return => 'no go' */ Node* Plant::findLoc(Node* here, const Location& location) { if (here == NULL) return NULL; if (here->loc == location) return here; if (here->isLeaf) return here; Node* result = NULL; for (int i = 0; i < here->sizeLinksArray; ++i) { result = findLoc(here->links[i], location); if (result != NULL && !(result->isLeaf) && result->loc == location) return result; } return NULL; } int Plant::nodeCount(Node* start) { cout << "Entering nodeCount " << endl; if (start == NULL) return 0; else if (start->numLinks == 0) return 1; cout << "Start->numLinks: " << start->numLinks << endl; int numOfNodes = 0; for (int i =0; i < start->sizeLinksArray; ++i) { if (start->links[i] != NULL) { numOfNodes += nodeCount(start->links[i]); } } cout << "Exit nodeCount" << endl; return numOfNodes + 1; } //Node& findNode(Location node) void Plant::printPov(Node* here) { if (here == NULL) return; else if (here->isLeaf) { printPovLeaf(here); return; } else { printPovBranchPoint(here); for (int i = 0; i < here->sizeLinksArray; ++i) { if (here->links[i] != NULL) { printPovBranch(here, here->links[i]); printPov(here->links[i]); } } } } void Plant::printPovBranchPoint(Node* here) { cout << "sphere { <" << here->loc.x << ", " << here->loc.y << ", " << here->loc.z << ">, 1" << endl; cout << "/t pigment{ color Green }" << endl; cout << "}" << endl << endl; } void Plant::printPovBranch(Node* here, Node* to) { cout << "cylinder { <" << here->loc.x << ", " << here->loc.y << ", " << here->loc.z << ">, <" << to->loc.x << ", " << to->loc.y << ", " << to->loc.z << ">, 0.5 }" << endl << endl; } void Plant::printPovLeaf(Node* here) { if (false) { } else { cout << "sphere { <" << here->loc.x << ", " << here->loc.y << ", " << here->loc.z << ">, 1" << endl << "/t pigment{ color Green }" << endl << "}" << endl << endl; } } double Plant::leafBenefit() { if (Sun == DOWN && leafFunction == CUBE) { return 5.0; } if (Sun == DOWN && leafFunction == RECTANGLE) { // calculate area of each leaf by projecting onto x-y plane // return 5.5; } if (Sun == DOWN && leafFunction == SPHERE) { // create a leaf* array // iterate through all the leaves // For each leaf add their area to the running total // check the distance between them and each leaf in the // leaf* array. if the distance is smaller than the radius // subtract the overlap // then add them to the leaf* array double total = 0; Node** leaves( int j = 0; int m = 0; for (PlantIterator i(root); i; ++i) { if (i.current->isLeaf) { total = (Math::PI)*(i.current->leafLength)^2; for (int z = 0; z < m; ++z) { int n = i.current->distance(leaves[z]); if (n < (i.current->leafLength + leaves[z]->leafLength)) { // random rough calculation version total = total - ((i.current->leafLength) - 0.5*n)^2; } } leaves[m] = i.current; ++m; } ++j; } return total; } // Down Sun, Sphere Leaves else return 6.0; } double Plant::structCost() { if (structFunction == X) { return totalLength(root) + leafCount(root); } else return 6.0; } double Plant::totalLength(Node* input) { if (input == NULL || input->isLeaf) return 0; double total = 0; for (int i = 0; i < input->sizeLinksArray; ++i) { if (input->links[i] != NULL & !(input->links[i]->isLeaf)) total += (input->loc).distance((input->links[i])->loc) + totalLength(input->links[i]); } return total; } double Plant::leafCount(Node* input) { if (input->isLeaf) return 1; return 0; }