/// <summary> /// Function that generates the bars between the first and last bar of the set, according to the layout rule /// </summary> /// <param name="firstCurve"></param> /// <param name="lastCurve"></param> /// <param name="layout"></param> /// <param name="nbOfBars"></param> /// <param name="spacing"></param> /// <param name="curves"></param> /// <param name="overrideCurve"></param> /// <returns></returns> private bool generateSet(Curve firstCurve, Curve lastCurve, RebarLayoutRule layout, int nbOfBars, double spacing, ref List <Curve> curves, Curve overrideCurve) { try { Line startLine = Line.CreateBound(firstCurve.Evaluate(0, true), lastCurve.Evaluate(0, true)); Line endLine = Line.CreateBound(firstCurve.Evaluate(1, true), lastCurve.Evaluate(1, true)); int barNumber = nbOfBars - 2; //see how many bar we can fit int numberOfBarsWhichCanFit = (int)((startLine.Length - double.Epsilon) / spacing) + 2; if (layout == RebarLayoutRule.NumberWithSpacing && numberOfBarsWhichCanFit != nbOfBars) //check if required number of bars fits between ends { return(false); } if (layout == RebarLayoutRule.MaximumSpacing || layout == RebarLayoutRule.MinimumClearSpacing) { barNumber = numberOfBarsWhichCanFit - 2; } double nEval = 0.0; for (int ii = 0; ii < barNumber; ii++) { nEval = (double)(ii + 1) / (double)(barNumber + 1); Curve newBar = (overrideCurve != null) ? overrideCurve.CreateTransformed(Transform.CreateTranslation(startLine.Evaluate(nEval, true) - overrideCurve.GetEndPoint(0))) : Line.CreateBound(startLine.Evaluate(nEval, true), endLine.Evaluate(nEval, true)); curves.Add(newBar); } } catch { return(false); } return(true); }
/// <summary> /// Function used to compute the geometry information of the Rebar element during document regeneration. /// Geometry information includes: /// 1. Graphical representation of the Rebar or Rebar Set; /// 2. Hook placement; /// 3. Distribution Path for MRA; /// /// </summary> /// <param name="data">Class used to pass information from the external application to the internal Rebar Element. /// Interfaces with the Rebar Element and exposes information needed for geometric calculation during regeneration, /// such as constrained geometry, state of changed input information, etc. /// Receives the result of the custom constraint calculation and /// updates the element after the entire function finished successfully. /// </param> /// <returns> true if geometry generation was completed successfully, false otherwise</returns> public bool GenerateCurves(RebarCurvesData data) { // used to store the faces and transforms used in generation of curves TargetFace firstFace = new TargetFace(); TargetFace secondFace = new TargetFace(); TargetFace thirdFace = new TargetFace(); //iterate through the available constraints and extract the needed information IList <RebarConstraint> constraints = data.GetRebarUpdateCurvesData().GetCustomConstraints(); foreach (RebarConstraint constraint in constraints) { if (constraint.NumberOfTargets > 1) { return(false); } Transform tempTrf = Transform.Identity; double dfOffset = 0; if (!getOffsetFromConstraintAtTarget(data.GetRebarUpdateCurvesData(), constraint, 0, out dfOffset)) { return(false); } switch ((BarHandle)constraint.GetCustomHandleTag()) { case BarHandle.FirstHandle: { Face face = constraint.GetTargetHostFaceAndTransform(0, tempTrf); firstFace = new TargetFace() { Face = face, Transform = tempTrf, Offset = dfOffset }; break; } case BarHandle.SecondHandle: { Face face = constraint.GetTargetHostFaceAndTransform(0, tempTrf); secondFace = new TargetFace() { Face = face, Transform = tempTrf, Offset = dfOffset }; break; } case BarHandle.ThirdHandle: { Face face = constraint.GetTargetHostFaceAndTransform(0, tempTrf); thirdFace = new TargetFace() { Face = face, Transform = tempTrf, Offset = dfOffset }; break; } default: break; } } // check if all the input is present for the calculation, otherwise return error(false). if (firstFace.Face == null || secondFace.Face == null || thirdFace.Face == null) { return(false); } Rebar thisBar = getCurrentRebar(data.GetRebarUpdateCurvesData()); CurveElement selectedCurve = null; //if a curve elem is selected, we override the geometry we get from the intersections and use the selected curve to create our bar geometries selectedCurve = getSelectedCurveElement(thisBar, data.GetRebarUpdateCurvesData()); //used to store the resulting curves List <Curve> curves = new List <Curve>(); Curve originalBar = null; Curve singleBar = getOffsetCurveAtIntersection(firstFace, secondFace); if (selectedCurve != null) { Transform trf = Transform.CreateTranslation(singleBar.GetEndPoint(0) - selectedCurve.GeometryCurve.GetEndPoint(0)); originalBar = singleBar; singleBar = selectedCurve.GeometryCurve.CreateTransformed(trf); } //we can't make any more bars without the first one. if (singleBar == null) { return(false); } // check the layout rule to see if we need to create more bars // for this example, any rule that is not single will generate bars in the same way, // creating them at an equal distance to each other, based only on number of bars RebarLayoutRule layout = data.GetRebarUpdateCurvesData().GetLayoutRule(); switch (layout) { case RebarLayoutRule.Single:// first bar creation: intersect first face with second face to get a curve curves.Add(singleBar); break; case RebarLayoutRule.FixedNumber: case RebarLayoutRule.NumberWithSpacing: case RebarLayoutRule.MaximumSpacing: case RebarLayoutRule.MinimumClearSpacing: curves.Add(singleBar); Curve lastBar = getOffsetCurveAtIntersection(firstFace, thirdFace);// create last bar // keep the curves pointing in the same direction var firstBar = (selectedCurve != null) ? originalBar : singleBar; if (lastBar == null || !alignBars(ref firstBar, ref lastBar)) { return(false); } if (selectedCurve != null) { Transform trf = Transform.CreateTranslation(lastBar.GetEndPoint(0) - selectedCurve.GeometryCurve.GetEndPoint(0)); lastBar = selectedCurve.GeometryCurve.CreateTransformed(trf); } if (!generateSet(singleBar, lastBar, layout, data.GetRebarUpdateCurvesData().GetBarsNumber(), data.GetRebarUpdateCurvesData().Spacing, ref curves, selectedCurve == null ? null : selectedCurve.GeometryCurve)) { return(false); } curves.Add(lastBar); break; default: break; } // check if any curves were created if (curves.Count <= 0) { return(false); } // create the distribution path for the bars that were created; // one single bar will not have a distribution path. List <Curve> distribPath = new List <Curve>(); for (int ii = 0; ii < curves.Count - 1; ii++) { distribPath.Add(Line.CreateBound(curves[ii].Evaluate(0.5, true), curves[ii + 1].Evaluate(0.5, true))); } // set distribution path if we have a path created if (distribPath.Count > 0) { data.SetDistributionPath(distribPath); } // add each curve as separate bar in the set. for (int ii = 0; ii < curves.Count; ii++) { List <Curve> barCurve = new List <Curve>(); barCurve.Add(curves[ii]); data.AddBarGeometry(barCurve); // set the hook normals for each bar added // important!: hook normals set here will be reset if bar geometry is changed on TrimExtendCurves // so they need to be recalculated then. for (int i = 0; i < 2; i++) { XYZ normal = computeNormal(curves[ii], firstFace, i); if (normal != null && !normal.IsZeroLength()) { data.GetRebarUpdateCurvesData().SetHookPlaneNormalForBarIdx(i, ii, normal); } } } return(true); }