/** * Make a clone of the stem at this position * * @param trf The base transformation for the clone * @param start_segm Start segment number, i.e. the height, where * the clone spreads out * @return The clone stem object */ CS_StemImpl make_clone(DX_Transformation trf, int start_segm) { // creates a clone stem with same atributes as this stem CS_StemImpl clone = new CS_StemImpl(tree, this, stemlevel, trf, offset); clone.segmentLength = segmentLength; clone.segmentCount = segmentCount; clone.length = length; clone.baseRadius = baseRadius; clone.splitCorrection = splitCorrection; clone.pruneTest = pruneTest; clone.index = index; //DBG("Stem.clone(): clone_index "+clone_index); clone.cloneIndex.AddRange(cloneIndex); //DBG("Stem.clone(): level: "+stemlevel+" clones "+clones); clone.cloneIndex.Add(clones.Count); if (!pruneTest) { clone.lengthChildMax = lengthChildMax; //clone.substem_cnt = substem_cnt; clone.substemsPerSegment = substemsPerSegment; //clone.substemdist = substemdist; //clone.substemdistv = substemdistv; //clone.seg_splits = self.seg_splits // FIXME: for more then one clone this angle should somehow // correspond to the rotation angle of the clone clone.substemRotangle = substemRotangle + 180; clone.leavesPerSegment = leavesPerSegment; } return(clone); }
/* (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)); }
public override bool visitLeaf(CS_Leaf leaf) { DX_Transformation transf = leaf.getTransformation(); List <DXMEV> mev = new List <DXMEV>(); foreach (DXMEV m in V) { DXMEV mp = new DXMEV(); mp.P = transf.apply(m.P); mp.P = new Vector4(mp.P.X, mp.P.Z, mp.P.Y, 1); mev.Add(mp); BBox.Maximum = Vector3.Max(BBox.Maximum, new Vector3(mp.P.X, mp.P.Y, mp.P.Z)); BBox.Minimum = Vector3.Min(BBox.Minimum, new Vector3(mp.P.X, mp.P.Y, mp.P.Z)); } int c = Vertices2[LEAFLEVEL].Count; foreach (int k in I) { Indices2[LEAFLEVEL].Add(c + k); } Vertices2[LEAFLEVEL].AddRange(mev); return(true); }
public override Vector3[] getSectionPoints(bool start = true) { CS_Params par = segment.par; CS_LevelParams lpar = segment.lpar; int pt_cnt = lpar.mesh_points; Vector3[] points; DX_Transformation trf = getTransformation(); //segment.getTransformation().translate(pos.sub(segment.getLowerPosition())); // if radius = 0 create only one point -> that's a problem for me if (false /*rad < -0.000001*/) { points = new Vector3[1]; points[0] = trf.apply(new Vector3(0, 0, 0)); } else { //create pt_cnt points points = new Vector3[pt_cnt]; //stem.DBG("MESH+LOBES: lobes: %d, depth: %f\n"%(self.tree.Lobes, self.tree.LobeDepth)) for (int i = 0; i < pt_cnt; i++) { float angle = i * 360.0f / pt_cnt; // for Lobes ensure that points are near lobes extrema, but not exactly there // otherwise there are to sharp corners at the extrema if (lpar.level == 0 && par.Lobes != 0) { angle -= 10.0f / par.Lobes; } // create some point on the unit circle Vector3 pt = new Vector3((float)Math.Cos(angle * Math.PI / 180), (float)Math.Sin(angle * Math.PI / 180), 0); // scale it to stem radius if (lpar.level == 0 && (par.Lobes != 0 || par._0ScaleV != 0)) { float rad1 = rad * (1 + par.random.uniform(-par._0ScaleV, par._0ScaleV) / segment.getSubsegmentCount()); pt = pt * (rad1 * (1.0f + par.LobeDepth * (float)Math.Cos(par.Lobes * angle * Math.PI / 180.0))); } else { pt = pt * rad; // faster - no radius calculations } // apply transformation to it // (for the first trunk segment transformation shouldn't be applied to // the lower meshpoints, otherwise there would be a gap between // ground and trunk) // FIXME: for helical stems may be/may be not a random rotation // should applied additionally? pt = trf.apply(pt); points[i] = pt; } } return(points); }
public override bool visitLeaf(CS_Leaf leaf) { DX_Transformation transf = leaf.getTransformation(); _lmh.AddLeaf(transf); return(true); }
/** * Creates a new stem * * @param tr the tree object * @param params the general tree parameters * @param lparams the parameters for the stem level * @param parnt the parent stem, from wich the stems grows out * @param stlev the stem level * @param trf the base transformation of the stem * @param offs the offset of ste stem within the parent stem (0..1) */ public CS_StemImpl(CS_TreeImpl tr, CS_StemImpl growsOutOf, int stlev, DX_Transformation trf, float offs) /* offs=0 */ { tree = tr; stemlevel = stlev; transf = trf; offset = offs; if (growsOutOf != null) { if (growsOutOf.stemlevel < stemlevel) { parent = growsOutOf; } else { clonedFrom = growsOutOf; parent = growsOutOf.parent; } } par = tree.csparams; lpar = par.getLevelParams(stemlevel); // initialize lists segments = new List <CS_SegmentImpl>(lpar.nCurveRes); if (lpar.nSegSplits > 0 || par._0BaseSplits > 0) { clones = new List <CS_StemImpl>(); // lpar.nSegSplits*lpar.nCurveRes+1); } if (stemlevel < par.Levels - 1) { CS_LevelParams lpar_1 = par.getLevelParams(lpar.level + 1); substems = new List <CS_StemImpl>(lpar_1.nBranches); } if (stemlevel == par.Levels - 1 && par.Leaves != 0) { leaves = new List <CS_LeafImpl>(Math.Abs(par.Leaves)); } // inialize other variables leavesPerSegment = 0; splitCorrection = 0; index = 0; // substem number cloneIndex = new List <int>(); pruneTest = false; // flag used for pruning //... maxPoint = new Vector3(-float.MaxValue, -float.MaxValue, -float.MaxValue); minPoint = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue); }
/** * Gives a clone a new direction (splitting) * * @param trf The base transformation of the clone * @param s_angle The splitting angle * @param nseg The segment number, where the clone begins * @param nsplits The number of clones * @return The new direction for the clone */ DX_Transformation split(DX_Transformation trf, float s_angle, int nseg, int nsplits) { // applies a split angle to the stem - the Weber/Penn method int remaining_seg = segmentCount - nseg - 1; // the splitangle // FIXME: don't know if it should be nSplitAngle or nSplitAngle/2 float declination = (float)(Math.Acos(trf.getZ3().Z) * 180 / Math.PI); float split_angle = Math.Max(0, (lpar.nSplitAngle + lpar.var(lpar.nSplitAngleV) - declination)); // FIXME: first works better for level 0, second for further levels // transf = transf.rotxz(split_angle,s_angle) trf = trf.rotx(split_angle); // adapt split correction splitCorrection -= split_angle / remaining_seg; //t_corr = Transformation().rotx(-split_angle/remaining_seg) float split_diverge; if (s_angle > 0) { // original stem has s_angle==0 if (par._0BaseSplits > 0 && stemlevel == 0 && nseg == 0) { split_diverge = s_angle + lpar.var(lpar.nSplitAngleV); } else { split_diverge = (float)(20 + 0.75 * (30 + Math.Abs(declination - 90)) * Math.Pow((lpar.var(1) + 1) / 2.0, 2)); if (lpar.var(1) >= 0) { split_diverge = -split_diverge; } } trf = trf.rotaxis(split_diverge, DX_Transformation.Z_AXIS); } else { split_diverge = 0; // for debugging only } // adjust some parameters //split_cnt = split_cnt+1; // lower substem prospensity if (!pruneTest) { substemsPerSegment /= (float)(nsplits + 1); // FIXME: same reduction for leaves_per_segment? } return(trf); }
/** * 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(); }
public void AddLeaf(DX_Transformation transf) { if (_leafType == 0) { MakeDiscPoints(5, transf); } else if (_leafType == 1) { MakeDiscPoints(3, transf); } else if (_leafType == 2) { MakeDiscPoints(4, transf); } else if (_leafType == 3) { MakeDiscPoints(5, transf); } else if (_leafType == 4) { MakeDiscPoints(6, transf); } else if (_leafType == 5) { MakeDiscPoints(7, transf); } else if (_leafType == 6) { MakeDiscPoints(8, transf); } else if (_leafType == 7) { MakeDiscPoints(9, transf); } else if (_leafType == 8) { MakeDiscPoints(10, transf); } else if (_leafType == 9) { MakeDiscPoints(11, transf); } else if (_leafType == 10) { MakeDiscPoints(4, transf); } //else if (_leafType == 11) MakeSpherePoints(); }
/** * Calcs the position of a substem in the segment given * a relativ position where in 0..1 - needed esp. for helical stems, * because the substems doesn't grow from the axis of the segement * * @param trf the transformation of the substem * @param where the offset, where the substem spreads out * @return the new transformation of the substem (shifted from * the axis of the segment to the axis of the subsegment) */ public DX_Transformation substemPosition(DX_Transformation trf, float where) { if (lpar.nCurveV >= 0) // normal segment { return(trf.translate(transf.getZ3() * (where * length))); } else // helix // get index of the subsegment { int i = (int)(where * (subsegments.Count - 1)); // interpolate position Vector3 p1 = ((CS_SubsegmentImpl)subsegments[i]).pos; Vector3 p2 = ((CS_SubsegmentImpl)subsegments[i + 1]).pos; Vector3 pos = p1 + (p2 - p1) * (where - i / (subsegments.Count - 1)); return(trf.translate(pos - getLowerPosition())); } }
/** * Leaf rotation toward light */ private void setLeafOrientation(CS_Params par) { if (par.LeafBend == 0) { return; } // FIXME: make this function as fast as possible - a tree has a lot of leafs // rotation outside Vector3 pos = transf.getT(); // the z-vector of transf is parallel to the // axis of the leaf, the y-vector is the normal // (of the upper side) of the leaf Vector3 norm = transf.getY3(); float tpos = (float)(Math.Atan2(pos.Y, pos.X) * 180 / Math.PI); float tbend = tpos - (float)(Math.Atan2(norm.Y, norm.X) * 180 / Math.PI);; // if (tbend>180) tbend = 360-tbend; float bend_angle = par.LeafBend * tbend; // transf = transf.rotz(bend_angle); // rotate about global z-axis transf = transf.rotaxis(bend_angle, DX_Transformation.Z_AXIS); // rotation up norm = transf.getY3(); float fbend = (float)(Math.Atan2((float)Math.Sqrt(norm.X * norm.X + norm.Y * norm.Y), norm.Z) * 180 / Math.PI); bend_angle = par.LeafBend * fbend; transf = transf.rotx(bend_angle); // this is from the paper, but is equivalent with // local x-rotation (upper code line) // // double orientation = Vector.atan2(norm.getY(),norm.getX()); // transf = transf // .rotaxis(-orientation,Vector.Z_AXIS) // .rotx(bend_angle) // .rotaxis(orientation,Vector.Z_AXIS); }
public CS_SegmentImpl(/*Params params, LevelParams lparams,*/ CS_StemImpl stm, int inx, DX_Transformation trf, float r1, float r2) { index = inx; transf = trf; rad1 = r1; rad2 = r2; stem = stm; par = stem.par; lpar = stem.lpar; length = stem.segmentLength; // FIXME: rad1 and rad2 could be calculated only when output occurs (?) // or here in the constructor ? // FIXME: inialize subsegs with a better estimation of size subsegments = new List <CS_SubsegmentImpl>(10); }
/** * 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)); }
private void MakeDiscPoints(int vCount, DX_Transformation transf) { List <DXBaseArbaroTreeMesh.DXVertex> dxvv = new List <DXBaseArbaroTreeMesh.DXVertex>(); // Create vertices for (int i = 0; i < vCount; i++) { float a = (float)(i * Math.PI * 2 / vCount); Vector4 p = new Vector4((float)Math.Sin(a), 0, (float)Math.Cos(a), 1); if (a < Math.PI) { p.X -= leaffunc(a); } else if (a > Math.PI) { p.X += leaffunc((float)(2 * Math.PI - a)); } p.X *= _width; p.Y *= _width; p.Z = (_stemLength + p.Z + 1) * _length; p = transf.apply(p); DXBaseArbaroTreeMesh.DXVertex dxv = _mesh.Vertices.Add(new DXArbaroVertexTrait(new Vector3(p.X, p.Y, p.Z))); dxvv.Add(dxv); } // create faces for (int i = 0; i < vCount - 2; i++) { //Console.WriteLine(dxvv[0].Index + " " + dxvv[i + 1].Index + " " + dxvv[i + 2].Index); _mesh.Faces.Add(dxvv[0], dxvv[i + 1], dxvv[i + 2]); } }
public override bool visitLeaf(CS_Leaf leaf) { DXSKV v0, v1; DX_Transformation transf = leaf.getTransformation(); // the tree is caculated in openGL coordinates with Z "up" so... v0.P = new Vector3(0, 0, 0); v1.P = new Vector3(0, 0, _csParams.LeafScale); v0.P = transf.apply(v0.P); v0.P = new Vector3(v0.P.X, v0.P.Z, v0.P.Y); v1.P = transf.apply(v1.P); v1.P = new Vector3(v1.P.X, v1.P.Z, v1.P.Y); v0.C = colors[5]; v1.C = colors[5]; BBox.Maximum = Vector3.Max(BBox.Maximum, v0.P); BBox.Maximum = Vector3.Max(BBox.Maximum, v1.P); BBox.Minimum = Vector3.Min(BBox.Minimum, v0.P); BBox.Minimum = Vector3.Min(BBox.Minimum, v1.P); Vertices2[LEAFLEVEL].Add(v0); Vertices2[LEAFLEVEL].Add(v1); return(true); }
/** * Make clones of the current stem at the current segment * * @param trf The current segments's direction * @param nseg The number of the current segment * @return Segments outside the pruning envelope, -1 * if stem clone is completely inside the envelope */ int makeClones(DX_Transformation trf, int nseg) { // splitting // FIXME: maybe move this calculation to LevelParams // but pay attention to saving errorValues and restoring when making prune tests int seg_splits_eff; if (stemlevel == 0 && nseg == 0 && par._0BaseSplits > 0) { seg_splits_eff = par._0BaseSplits; } else { // how many clones? float seg_splits = lpar.nSegSplits; seg_splits_eff = (int)(seg_splits + lpar.splitErrorValue + 0.5); // adapt error value lpar.splitErrorValue -= (seg_splits_eff - seg_splits); } if (seg_splits_eff < 1) { return(-1); } float s_angle = 360 / (seg_splits_eff + 1); // make clones // if seg_splits_eff > 0: for (int i = 0; i < seg_splits_eff; i++) { // copy params CS_StemImpl clone = make_clone(trf, nseg + 1); // NOTE: its a little bit problematic here // when the clone is given as a parent to // the substems, it should have the same // params for length and segment_cnt like // the original stem, but this could be // somewhat confusing(?) // clone.segment_cnt = remaining_segs; // clone.length = remaining_segs * self.segment_len // change the direction for the clone //if self.debug: sys.stderr.write("-SPLIT_CORE_BEFOR: %s, dir: %s\n" % \ // (str(clone.split_corr),str(clone.direction))) clone.transf = clone.split(trf, s_angle * (1 + i), nseg, seg_splits_eff); //if self.debug: sys.stderr.write("-SPLIT_CORE_AFTER: %s, dir: %s\n" % // (str(clone.split_corr),str(clone.direction))) // make segments etc. for the clone int segm = clone.makeSegments(nseg + 1, clone.segmentCount); if (segm >= 0) { // prune test - clone not inside envelope return(segm); } // add clone to the list clones.Add(clone); } // get another direction for the original stem too trf = split(trf, 0, nseg, seg_splits_eff); return(-1); }
/** * 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()); } } }
/** * Calcs a new direction for the current segment * * @param trf The transformation of the previous segment * @param nsegm The number of the segment ( for testing, if it's the * first stem segment * @return The new transformation of the current segment */ DX_Transformation newDirection(DX_Transformation trf, int nsegm) { // next segments direction // The first segment shouldn't get another direction // down and rotation angle shouldn't be falsified if (nsegm == 0) { return(trf); } /* * if (Console.debug()) * TRF("Stem.new_direction() before curving",trf); */ // get curving angle double delta; if (lpar.nCurveBack == 0) { delta = lpar.nCurve / lpar.nCurveRes; } else { if (nsegm < (lpar.nCurveRes + 1) / 2) { delta = lpar.nCurve * 2 / lpar.nCurveRes; } else { delta = lpar.nCurveBack * 2 / lpar.nCurveRes; } } delta += splitCorrection; /* * if (Console.debug()) * DBG("Stem.new_direction(): delta: "+delta); */ trf = trf.rotx(delta); // With Weber/Penn the orientation of the x- and y-axis // shouldn't be disturbed (maybe, because proper curving relies on this) // so may be such random rotations shouldn't be used, instead nCurveV should // add random rotation to rotx, and rotate nCurveV about the tree's z-axis too? // add random rotation about z-axis if (lpar.nCurveV > 0) { // if (nsegm==0 && stemlevel==0) { // first_trunk_segment // // random rotation more moderate // delta = (Math.abs(lpar.var(lpar.nCurveV)) - // Math.abs(lpar.var(lpar.nCurveV))) // / lpar.nCurveRes; // } else { // full random rotation delta = lpar.var(lpar.nCurveV) / lpar.nCurveRes; // } // self.DBG("curvV (delta): %s\n" % str(delta)) double rho = 180 + lpar.var(180); trf = trf.rotaxisz(delta, rho); } //TRF("Stem.new_direction() after curving",trf); // attraction up/down if (par.AttractionUp != 0 && stemlevel >= 2) { double declination = Math.Acos(trf.getZ3().Z); // I don't see, why we need orientation here, may be this avoids // attraction of branches with the x-Axis up and thus avoids // twisting (see below), but why branches in one direction should // be attracted, those with another direction not, this is unnaturally: // double orient = Math.acos(trf.getY().getZ()); // double curve_up_orig = par.AttractionUp * declination * Math.cos(orient)/lpar.nCurveRes; // FIXME: devide by (lpar.nCurveRes-nsegm) if last segment // should actually be vertical double curve_up = par.AttractionUp * Math.Abs(declination * Math.Sin(declination)) / lpar.nCurveRes; Vector3 z = trf.getZ3(); // FIXME: the mesh is twisted for high values of AttractionUp trf = trf.rotaxis(-curve_up * 180 / Math.PI, new Vector3(-z.Y, z.X, 0)); // trf = trf.rotx(curve_up*180/Math.PI); } return(trf); }
// makes the segments of the stem int makeSegments(int start_seg, int end_seg) { // if (start_seg>end_seg) throw new ArbaroException("Error in segment creation end_seg<start_seg."); if (stemlevel == 1) { tree.updateGenProgress(); } //if (par.verbose) { /* * if (! pruneTest) { * if (stemlevel==0) Console.progressChar('='); * else if (stemlevel==1 && start_seg==0) Console.progressChar('/'); * else if (stemlevel==2 && start_seg==0) Console.progressChar(); * } * //} */ DX_Transformation trf = transf; for (int s = start_seg; s < end_seg; s++) { if (stemlevel == 0) { tree.updateGenProgress(); } if (!pruneTest) {// && par.verbose) { //if (stemlevel==0) Console.progressChar('|'); } // curving trf = newDirection(trf, s); /* * if (Console.debug()) * TRF("Stem.make_segments(): after new_direction ",trf); */ // segment radius float rad1 = stemRadius(s * segmentLength); float rad2 = stemRadius((s + 1) * segmentLength); // create new segment CS_SegmentImpl segment = new CS_SegmentImpl(this, s, trf, rad1, rad2); segment.make(); segments.Add(segment); // create substems // self.DBG("SS-makingsubst? pt: %d, lev: %d\n"%(self.prunetest,self.level)) if (!pruneTest && lpar.level < par.Levels - 1) { // self.DBG("SS-making substems\n") makeSubstems(segment); } if (!pruneTest && lpar.level == par.Levels - 1 && par.Leaves != 0) { makeLeaves(segment); } // shift to next position trf = trf.translate(trf.getZ3() * (segmentLength)); //self.DBG("transf: %s\n"%(transf)) //self.DBG("pos: %s\n"%(transf.vector)) // test if too long if (pruneTest && !isInsideEnvelope(trf.getT())) { // DBG("PRUNE: not inside - return %d\n"%(s)) return(s); } // splitting (create clones) if (s < end_seg - 1) { int segm = makeClones(trf, s); // trf is changed by make_clones // prune test - clone not inside envelope if (segm >= 0) { //DBG("PRUNE: clone not inside - return %d\n"%(segm)) return(segm); } } } return(-1); }
/** * 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); } } } }
/** * For debugging: * Prints out the transformation to stderr nicely * (only if debugging is enabled) * * @param where The position in the tree, i.e. wich stem * has this transformation * @param trf The transformation */ void TRF(String where, DX_Transformation trf) { //DBG(where + ": " + trf.toString()); }
public CS_LeafImpl(DX_Transformation trf) { // par = params; transf = trf; }