private IIlluminationArea CreateIllumShadow(Tuple <Point2d, double> angleStart, Tuple <Point2d, double> angleEnd) { if (angleEnd.Item2 - angleStart.Item2 > Math.PI) { // Переворот начального и конечного угла var t1 = angleEnd; angleEnd = angleStart; angleStart = t1; } // если конечный угол меньше начального расчетного или наоборот, то тень вне границ расчета. Или если начальный угол = конечному if (angleEnd.Item2 < StartAnglesIllum.AngleStartOnPlane || angleStart.Item2 > StartAnglesIllum.AngleEndOnPlane || angleStart.Item2.IsEqual(angleEnd.Item2, 0.001)) { return(null); } if (angleStart.Item2 < StartAnglesIllum.AngleStartOnPlane) { var ptStart = IllumAreaBase.GetPointInRayFromPoint(ptCalc2d, angleStart.Item1, StartAnglesIllum.AngleStartOnPlane); angleStart = new Tuple <Point2d, double>(ptStart, StartAnglesIllum.AngleStartOnPlane); } if (angleEnd.Item2 > StartAnglesIllum.AngleEndOnPlane) { var ptEnd = IllumAreaBase.GetPointInRayFromPoint(ptCalc2d, angleEnd.Item1, StartAnglesIllum.AngleEndOnPlane); angleEnd = new Tuple <Point2d, double>(ptEnd, StartAnglesIllum.AngleEndOnPlane); } var ilum = new IllumAreaCentral(insPt, ptCalc2d, angleStart.Item2, angleEnd.Item2, angleStart.Item1, angleEnd.Item1); return(ilum); }
private List <IIlluminationArea> CalcIllumsByHeight(List <MapBuilding> buildings, double height) { List <IIlluminationArea> illumShadows = new List <IIlluminationArea>(); using (Line lineShadow = GetLineShadow(height)) { // перебор домов одной высоты foreach (var build in buildings) { // Если дом полностью выше линии тени (сечения), то он полностью затеняет точку if (build.YMin >= (lineShadow.StartPoint.Y - 0.1)) { // Найти точку начала тени и конца (с минимальным и макс углом к точке расчета) var ilumShadow = GetBuildingZeroLineShadows(build); //var ilumShadow = GetIllumShadow(build.Contour.GetPoints().Where(p=>p.Y<ptCalc.Y).ToList()); if (ilumShadow != null) { illumShadows.Add(ilumShadow); } } else if (build.YMax >= (lineShadow.StartPoint.Y - 0.1)) { var ilumsBoundary = GetBuildingLineShadowBoundary(build, lineShadow, Intersect.ExtendThis); illumShadows.AddRange(ilumsBoundary); } } #if TEST EntityHelper.AddEntityToCurrentSpace(lineShadow); #endif } // Объединение совпадающих зон теней illumShadows = IllumAreaBase.Merge(illumShadows); return(illumShadows); }
///// <summary> ///// Начальный угол в плане (радиан). Начальное значение = 0 - восход. ///// Будут определены для этой расвчетной точки индивидуально ///// </summary> //public double AngleStartOnPlane { get; private set; } ///// <summary> ///// Конечный угол в плане (радиан). Начальное значение = 180 - заход ///// </summary> //public double AngleEndOnPlane { get; private set; } public CalcPointCentral(InsPoint insPt, CalcServiceCentral insCalcService) { this.map = insPt.Model.Map; buildingOwner = insPt.Building; this.insPt = insPt; ptCalc = insPt.Point; ptCalc2d = ptCalc.Convert2d(); this.calc = insCalcService; values = insCalcService.CalcValues; //AngleStartOnPlane = values.SunCalcAngleStartOnPlane; //AngleEndOnPlane = values.SunCalcAngleEndOnPlane; StartAnglesIllum = new IllumAreaBase(insPt, ptCalc2d, values.SunCalcAngleStartOnPlane, values.SunCalcAngleEndOnPlane, Point2d.Origin, Point2d.Origin); }
/// <summary> /// Корректировка стартовых углов инсоляции от расчетной точки которая находится на вершине полилинии контура здания /// </summary> /// <param name="vertexIndex">Индекс вершины - расчетной точки</param> private void CorrectStartAnglesByOwnerCorner(int vertexIndex) { var contour = buildingOwner.Contour; var nextIndex = contour.NextVertexIndex(vertexIndex, -1); var seg = contour.GetLineSegment2dAt(vertexIndex); var segNext = contour.GetLineSegment2dAt(nextIndex); // Область освещения от угла контура - от 1 сегмента до 2 (угол вне дома) var cornerIllum = new IllumAreaBase(insPt, ptCalc2d, seg.Direction.Angle, segNext.Direction.Negate().Angle, Point2d.Origin, Point2d.Origin); // Проверка - если средний вектор внутри здания, то инвертировать область var midVec = cornerIllum.GetMidVector(); var ptMid = ptCalc2d + midVec; if (!contour.IsPointInsidePolygon(ptMid.Convert3d())) { // инвертировать область cornerIllum.Invert(); } var eastAngle = values.GetInsAngleFromAcad(cornerIllum.AngleStartOnPlane); CorrectEastStartAngle(eastAngle); CorrectWestStartAngle(values.GetInsAngleFromAcad(cornerIllum.AngleEndOnPlane)); }
public List <IIlluminationArea> Calc() { var resAreas = new List <IIlluminationArea>(); // Корректировка расчетной точки if (!CorrectCalcPoint()) { return(null); } // Проверка - если точка расположена внутри другого дома (кроме собственного), то вся точка в тени if (IsCalcPointInsideOtherBuilding()) { throw new Exception("Расчтеная точка попадает на соседнее здание."); //return null; } // Определение ограничений углов (начального и конечного) с учетом плоскости стены расчетного дома if (DefineStartAnglesByOwnerBuilding()) { // расчетные граници (по заданным расчетным углам) var ext = GetCalcExtents(map.MaxBuildingHeight); // кусок карты using (var scope = map.GetScope(ext)) { // исключение из списка домов собственно расчетного дома if (buildingOwner != null) { scope.Buildings.Remove(buildingOwner); } // Добавление отсеченных частей здания от собственного здания расчетной точки if (secantBuildings != null) { foreach (var item in secantBuildings) { item.InitContour(); } scope.Buildings.AddRange(secantBuildings); } // Расчет зон теней // группировка домов по высоте var heights = scope.Buildings.GroupBy(g => g.HeightCalc); double ptHeightCalc = GetPtCalcHeight(); foreach (var bHeight in heights) { double heightCalc = GetHeightCalcBuilding(ptHeightCalc, bHeight.Key); if (heightCalc == 0) { continue; } var illumsByHeight = CalcIllumsByHeight(bHeight.ToList(), heightCalc); if (illumsByHeight != null && illumsByHeight.Any()) { resAreas.AddRange(illumsByHeight); } } } resAreas = IllumAreaBase.Merge(resAreas); // Инвертировать зоны теней в зоны освещенностей resAreas = IllumAreaCentral.Invert(resAreas, StartAnglesIllum, ptCalc2d, insPt); } else { StartAnglesIllum.AngleEndOnPlane = 0; StartAnglesIllum.AngleStartOnPlane = 0; } return(resAreas); }