/* (non-Javadoc) * @see net.sourceforge.arbaro.tree.TraversableTree#traverseTree(net.sourceforge.arbaro.tree.TreeTraversal) */ DX_Transformation trunkDirection(DX_Transformation trf, CS_LevelParams lpar) { // get rotation angle double rotangle; if (lpar.nRotate >= 0) { // rotating trunk trunk_rotangle = (trunk_rotangle + lpar.nRotate + lpar.var(lpar.nRotateV) + 360) % 360; rotangle = trunk_rotangle; } else { // alternating trunks if (Math.Abs(trunk_rotangle) != 1) { trunk_rotangle = 1; } trunk_rotangle = -trunk_rotangle; rotangle = trunk_rotangle * (180 + lpar.nRotate + lpar.var(lpar.nRotateV)); } // get downangle double downangle; downangle = lpar.nDownAngle + lpar.var(lpar.nDownAngleV); return(trf.rotxz(downangle, rotangle)); }
/** * Generates the tree. The following collaboration diagram * shows the recursion trough the make process: * <p> * <img src="doc-files/Tree-2.png" /> * <p> * * @throws Exception */ public void make(Object progress) { this.progress = progress; setupGenProgress(); csparams.prepare(seed); maxPoint = new Vector3(-float.MaxValue, -float.MaxValue, -float.MaxValue); minPoint = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue); Console.WriteLine("Tree species: " + csparams.Species + ", Seed: " + seed); Console.WriteLine("making " + csparams.Species + "(" + seed + ") "); // create the trunk and all its stems and leaves DX_Transformation transf = new DX_Transformation(); DX_Transformation trf; float angle; float dist; CS_LevelParams lpar = csparams.getLevelParams(0); for (int i = 0; i < lpar.nBranches; i++) { trf = trunkDirection(transf, lpar); angle = lpar.var(360); dist = lpar.var(lpar.nBranchDist); trf = trf.translate(new Vector3(dist * (float)Math.Sin(angle), dist * (float)Math.Cos(angle), 0)); CS_StemImpl trunk = new CS_StemImpl(this, null, 0, trf, 0); trunks.Add(trunk); trunk.index = 0; trunk.make(); } // set leafCount and stemCount for the tree if (csparams.Leaves == 0) { setLeafCount(0); } else { CS_LeafCounter leafCounter = new CS_LeafCounter(); traverseTree(leafCounter); setLeafCount(leafCounter.getLeafCount()); } CS_StemCounter stemCounter = new CS_StemCounter(); traverseTree(stemCounter); setStemCount(stemCounter.getStemCount()); // making finished Console.WriteLine("making " + csparams.Species + " Done. "); // TODO //progress.endPhase(); }
/** * Calcs the direction of a substem from the parameters * * @param trf The transformation of the current stem segment * @param offset The offset of the substem from the base of the currents stem * @return The direction of the substem */ DX_Transformation substemDirection(DX_Transformation trf, float offset) { CS_LevelParams lpar_1 = par.getLevelParams(stemlevel + 1); //lev = min(level+1,3); // get rotation angle float rotangle; if (lpar_1.nRotate >= 0) { // rotating substems substemRotangle = (substemRotangle + lpar_1.nRotate + lpar_1.var(lpar_1.nRotateV) + 360) % 360; rotangle = substemRotangle; } else { // alternating substems if (Math.Abs(substemRotangle) != 1) { substemRotangle = 1; } substemRotangle = -substemRotangle; rotangle = substemRotangle * (180 + lpar_1.nRotate + lpar_1.var(lpar_1.nRotateV)); } // get downangle float downangle; if (lpar_1.nDownAngleV >= 0) { downangle = lpar_1.nDownAngle + lpar_1.var(lpar_1.nDownAngleV); } else { float len = (stemlevel == 0) ? length * (1 - par.BaseSize) : length; downangle = lpar_1.nDownAngle + lpar_1.nDownAngleV * (1 - 2 * par.getShapeRatio((length - offset) / len, 0)); } /* * if (Console.debug()) * DBG("Stem.substem_direction(): down: "+downangle+" rot: "+rotangle); */ return(trf.rotxz(downangle, rotangle)); }
/** * Precalcs some stem parameters used later during when generating * the current stem */ void prepareSubstemParams() { //int level = min(stemlevel+1,3); CS_LevelParams lpar_1 = par.getLevelParams(stemlevel + 1); // maximum length of a substem lengthChildMax = lpar_1.nLength + lpar_1.var(lpar_1.nLengthV); // maximum number of substems float stems_max = lpar_1.nBranches; // actual number of substems and substems per segment float substem_cnt; if (stemlevel == 0) { substem_cnt = stems_max; substemsPerSegment = (float)(substem_cnt / (float)segmentCount / (1 - par.BaseSize)); /* * if (Console.debug()) * DBG("Stem.prepare_substem_params(): stems_max: "+ substem_cnt + " substems_per_segment: " + substemsPerSegment); */ } else if (par.preview) { substem_cnt = stems_max; substemsPerSegment = (float)(substem_cnt / segmentCount); } else if (stemlevel == 1) { substem_cnt = (int)(stems_max * (0.2 + 0.8 * length / parent.length / parent.lengthChildMax)); substemsPerSegment = substem_cnt / (float)segmentCount; /*DBG("Stem.prepare_substem_params(): substem_cnt: "+ substem_cnt + " substems_per_segment: " + substemsPerSegment);*/ } else { substem_cnt = (int)(stems_max * (1.0 - 0.5 * offset / parent.length)); substemsPerSegment = substem_cnt / (float)segmentCount; } substemRotangle = 0; // how much leaves for this stem - not really a substem parameter if (lpar.level == par.Levels - 1) { leavesPerSegment = leavesPerBranch() / segmentCount; } }
/** * Calcs stem length from parameters and parent length * * @return the stem length */ float stemLength() { if (stemlevel == 0) { // trunk return((lpar.nLength + lpar.var(lpar.nLengthV)) * par.scale_tree); } else if (stemlevel == 1) { float parlen = parent.length; float baselen = par.BaseSize * par.scale_tree; float ratio = (parlen - offset) / (parlen - baselen); /* * if (Console.debug()) * DBG("Stem.stem_length(): parlen: "+parlen+" offset: "+offset+" baselen: "+baselen+" ratio: "+ratio); */ return(parlen * parent.lengthChildMax * par.getShapeRatio(ratio)); } else { // higher levels return((float)(parent.lengthChildMax * (parent.length - 0.6 * offset))); } }
/** * Make substems of the current stem * * @param segment */ void makeSubstems(CS_SegmentImpl segment) { // creates substems for the current segment CS_LevelParams lpar_1 = par.getLevelParams(stemlevel + 1); /* * if (Console.debug()) * DBG("Stem.make_substems(): substems_per_segment "+substemsPerSegment); */ float subst_per_segm; float offs; if (stemlevel > 0) { // full length of stem can have substems subst_per_segm = substemsPerSegment; if (segment.index == 0) { offs = parent.stemRadius(offset) / segmentLength; } else { offs = 0; } } else if (segment.index * segmentLength > par.BaseSize * length) { // segment is fully out of the bare trunk region => normal nb of substems subst_per_segm = substemsPerSegment; offs = 0; } else if ((segment.index + 1) * segmentLength <= par.BaseSize * length) { // segment is fully part of the bare trunk region => no substems return; } else { // segment has substems in the upper part only offs = (par.BaseSize * length - segment.index * segmentLength) / segmentLength; subst_per_segm = substemsPerSegment * (1 - offs); } // how many substems in this segment int substems_eff = (int)(subst_per_segm + lpar.substemErrorValue + 0.5); // adapt error value lpar.substemErrorValue -= (substems_eff - subst_per_segm); if (substems_eff <= 0) { return; } //DBG("Stem.make_substems(): substems_eff: "+substems_eff); // what distance between the segements substems float dist = (1.0f - offs) / substems_eff * lpar_1.nBranchDist; float distv = dist * 0.25f; // lpar_1.nBranchDistV/2; //DBG("Stem.make_substems(): offs: "+offs+" dist: "+dist+" distv: "+distv); for (int s = 0; s < substems_eff; s++) { // where on the segment add the substem float where = offs + dist / 2 + s * dist + lpar_1.var(distv); //offset from stembase float offset = (segment.index + where) * segmentLength; /* * DBG("Stem.make_substems(): offset: "+ offset+" segminx: "+segment.index +" where: "+where+ " seglen: "+segmentLength); */ DX_Transformation trf = substemDirection(segment.transf, offset); trf = segment.substemPosition(trf, where); // create new substem CS_StemImpl substem = new CS_StemImpl(tree, this, stemlevel + 1, trf, offset); substem.index = substems.Count; //DBG("Stem.make_substems(): make new substem"); if (substem.make()) { substems.Add(substem); // //if (substem.segments.size()==0) // throw new ArbaroException("No segments created for substem "+substem.getTreePosition()); } } }
/** * Creates the leaves for the current stem segment * * @param segment */ void makeLeaves(CS_SegmentImpl segment) { // creates leaves for the current segment if (par.Leaves > 0) { // ### NORMAL MODE, leaves along the stem // how many leaves in this segment float leaves_eff = (int)(leavesPerSegment + par.leavesErrorValue + 0.5); // adapt error value par.leavesErrorValue -= (leaves_eff - leavesPerSegment); if (leaves_eff <= 0) { return; } float offs; if (segment.index == 0) { offs = parent.stemRadius(offset) / segmentLength; } else { offs = 0; } // what distance between the leaves float dist = (1.0f - offs) / leaves_eff; for (int s = 0; s < leaves_eff; s++) { // where on the segment add the leaf // FIXME: may be use the same distribution method (BranchDist) as for substems? float where = offs + dist / 2 + s * dist + lpar.var(dist / 2); // offset from stembase float loffs = (segment.index + where) * segmentLength; // get a new direction for the leaf DX_Transformation trf = substemDirection(segment.transf, loffs); // translate it to its position on the stem trf = trf.translate(segment.transf.getZ3() * (where * segmentLength)); // create new leaf CS_LeafImpl leaf = new CS_LeafImpl(trf); // ,loffs); leaf.make(par); leaves.Add(leaf); } } // ##### FAN MOD, leaves placed in a fan at stem end else if (par.Leaves < 0 && segment.index == segmentCount - 1) { CS_LevelParams lpar_1 = par.getLevelParams(stemlevel + 1); int cnt = (int)(leavesPerBranch() + 0.5); DX_Transformation trf = segment.transf.translate(segment.transf.getZ3() * (segmentLength)); float distangle = lpar_1.nRotate / cnt; float varangle = lpar_1.nRotateV / cnt; float downangle = lpar_1.nDownAngle; float vardown = lpar_1.nDownAngleV; float offsetangle = 0; // use different method for odd and even number if (cnt % 2 == 1) { // create one leaf in the middle CS_LeafImpl leaf = new CS_LeafImpl(trf); //,segmentCount*segmentLength); leaf.make(par); leaves.Add(leaf); offsetangle = distangle; } else { offsetangle = distangle / 2; } // create leaves left and right of the middle for (int s = 0; s < cnt / 2; s++) { for (int rot = 1; rot >= -1; rot -= 2) { DX_Transformation transf1 = trf.roty(rot * (offsetangle + s * distangle + lpar_1.var(varangle))); transf1 = transf1.rotx(downangle + lpar_1.var(vardown)); CS_LeafImpl leaf = new CS_LeafImpl(transf1); //,segmentCount*segmentLength); leaf.make(par); leaves.Add(leaf); } } } }