unit U_ProjectPlan; interface uses Windows, Forms, StdCtrls, Classes, ComCtrls, Controls, DrawEngine, PCTypesUtils, SysUtils, Dialogs, Contnrs, DrawObjects, PCDrawBox, PCDrawing, PowerCad, Graphics, U_Cad, U_ESCadClasess, U_SCSLists, U_SCSComponent, U_SCSEngineTest, U_BaseCommon, U_Progress, U_Splash, Math, U_Navigator, Messages, U_Common, FastStrings; procedure DrawProjectPlan(aList: TF_CAD; aComponTypes: TObjectList; aDivideGroupsByJoinedNetTypes, aShowGroupContents: Boolean); Function DrawObjectsOnProjectPlan(aList: TF_CAD; aObjCatalog: TSCSCatalog; aCabBounds: TDoubleRect; aObjectX, aObjectY: Double): TPlanObject; procedure DrawTracesOnProjectPlan(aList: TF_CAD; aPlanProject: PPlanProject; aObjList: TObjectList); procedure DrawTraceWay(aList: TF_CAD; aPlanProject: PPlanProject; aBegObject, aEndObject: TPlanObject; aLinesNotes: TStringList; aBegObjectType, aEndObjectType: string); function GetListBound(aList: TF_CAD): TDoubleRect; function GetScaleNotesToBlock(aBlockBnd, aNoteBnd: TDoubleRect): Double; function GetBlockScale(aObject: TFigureGrp; aX, aY: double): Double; function FindPlanObject(aList: TF_CAD; aSCSID: Integer): TPlanObject; function CheckByPlanTrace(aX, aY: Double; aTracesList: TList): TPlanTrace; function CheckByPlanConnector(aX, aY: Double; aCurrConn1, aCurrConn2: TPlanConnector): TPlanConnector; function CheckPlanConnectorAtPos(aSelf: TPlanConnector; aX, aY: Double): Boolean; function CheckTypesIdentity(aCurrBegType, aCurrEndType, aSnapBegType, aSnapEndType: string): Boolean; // автопривязки function CheckPlanConnectorGoesToEndObject(aEndSCSID: Integer; aPlanConnector: TPlanConnector): Boolean; function CheckPlanTraceGoesToEndObject(aEndSCSID: Integer; aPlanTrace: TPlanTrace): Boolean; procedure SnapToPlanConnector(aConnector, aSnapConnector: TPlanConnector); procedure SnapToPlanTrace(aConnector: TPlanConnector; aSnapTrace: TPlanTrace); function FindSnapOnTraceTraffic(aPlanTrace: TPlanTrace; aEndObject: TPlanObject; aBegObjectType, aEndObjectType: string): Boolean; // создание подписи к группе трасс procedure CreatePlanTraceCaption(aPlanTrace: TPlanTrace; aCaption: TStringList); function GetPlanTraceAngle(aPoints1, aPoints2: TDoublePoint): Double; implementation uses USCS_Main, Menus, U_main, U_MasterNewList, U_AutoTraceType, U_Layers, FPlan, U_SCSObjectsProp, cxMemo, U_ChooseComponTypes, U_Constants; procedure DrawProjectPlan(aList: TF_CAD; aComponTypes: TObjectList; aDivideGroupsByJoinedNetTypes, aShowGroupContents: Boolean); var i, j, k: Integer; Bnd: TDoubleRect; LHandle: Integer; Rect: TRectangle; Line: TLine; Text: TText; MaketX, MaketY: Double; CurrProject: TSCSProject; StructuredLists: TSCSLists; ListCatalog: TSCSCatalog; FloorDelta: Double; CabDelta: Double; BegPosX, BegPosY: Double; CabBound: TDoubleRect; ObjGroup: TPlanObject; MaxX, MaxY: double; ptrPlanProject: PPlanProject; ptrPlanFloor: PPlanFloor; ptrPlanCabinet: PPlanCabinet; ConnectionsGroup: TCatalogGroupConnection; ObjList: TObjectList; NbrCircle: TCircle; NbrText: TText; CabCenter: TDoublePoint; begin try BeginProgress; GCadForm.Pcad.DefaultPenColor := clNavy; GCadForm.PCad.DefaultPenWidth := 2; GCadForm.PCad.DefaultPenStyle := psSolid; CurrProject := F_ProjMan.GSCSBase.CurrProject; StructuredLists := CurrProject.GetListsFilteredByComponentTypes(aComponTypes, aDivideGroupsByJoinedNetTypes, aShowGroupContents); aList.CurrentLayer := 1; Bnd := GetListBound(aList); MaketX := abs(Bnd.Left - Bnd.Right); MaketY := abs(Bnd.Bottom - Bnd.Top); LHandle := aList.PCad.GetLayerHandle(1); Rect := TRectangle.create(Bnd.Left, Bnd.Top, Bnd.Right, Bnd.Bottom, 1, ord(psDash), clBlack, ord(bsClear), clNone, LHandle, mydsNormal, aList.PCad); aList.PCad.AddCustomFigure(1, Rect, False); FloorDelta := MaketY / StructuredLists.Count; BegPosX := Bnd.Left; BegPosY := Bnd.Bottom; // Calc MaxX, MaxY MaxY := FloorDelta; MaxX := 0; for i := 0 to StructuredLists.Count - 1 do begin if i = 0 then // Tolik 16/11/2020 -- тут тоже деление на НОЛЬ исключаем... // MaxX := MaketX / StructuredLists[i].ChildCatalogs.Count begin if StructuredLists[i].ChildCatalogs.Count > 0 then MaxX := MaketX / StructuredLists[i].ChildCatalogs.Count else MaxX := MaketX; end // else // Tolik 14/11/2020 -- тут нужно исключить деление на НОЛЬ!!! //if MaketX / StructuredLists[i].ChildCatalogs.Count < MaxX then // MaxX := MaketX / StructuredLists[i].ChildCatalogs.Count; begin if StructuredLists[i].ChildCatalogs.Count > 0 then if MaketX / StructuredLists[i].ChildCatalogs.Count < MaxX then MaxX := MaketX / StructuredLists[i].ChildCatalogs.Count; end; end; // ! New(ptrPlanProject); ptrPlanProject.FSizeX := MaketX; ptrPlanProject.FSizeY := MaketY; ptrPlanProject.FBounds.Left := Bnd.Left; ptrPlanProject.FBounds.Right := Bnd.Right; ptrPlanProject.FBounds.Top := Bnd.Top; ptrPlanProject.FBounds.Bottom := Bnd.Bottom; ptrPlanProject.FFloors := TList.Create; // ! // ЭТАЖИ for i := 0 to StructuredLists.Count - 1 do begin BegPosX := Bnd.Left; BegPosY := BegPosY - FloorDelta; // ! New(ptrPlanFloor); ptrPlanFloor.FSizeX := MaketX; ptrPlanFloor.FSizeY := FloorDelta; ptrPlanFloor.FBounds.Left := BegPosX; ptrPlanFloor.FBounds.Right := BegPosX + ptrPlanFloor.FSizeX; ptrPlanFloor.FBounds.Top := BegPosY; ptrPlanFloor.FBounds.Bottom := BegPosY + ptrPlanFloor.FSizeY; ptrPlanFloor.FCabinets := TList.Create; // ! if i < StructuredLists.Count - 1 then begin // линию разделительную Line := TLine.Create(BegPosX, BegPosY, BegPosX + MaketX, BegPosY, 1, ord(psDash), clBlack, 0, LHandle, mydsNormal, aList.PCad); aList.PCad.AddCustomFigure(1, Line, False); end; // номер этажа Text := TText.Create(0, 0, 14, 8, IntToStr(i + 1), aList.FFontName, RUSSIAN_CHARSET, clGray, LHandle, mydsNormal, aList.PCad); Text.Move(BegPosX + 5 - Text.CenterPoint.x, BegPosY + FloorDelta / 2 - Text.CenterPoint.y); aList.PCad.AddCustomFigure(1, Text, False); Text := TText.Create(0, 0, 14, 8, IntToStr(i + 1), aList.FFontName, RUSSIAN_CHARSET, clGray, LHandle, mydsNormal, aList.PCad); Text.Move(BegPosX + MaketX - 5 - Text.CenterPoint.x, BegPosY + FloorDelta / 2 - Text.CenterPoint.y); aList.PCad.AddCustomFigure(1, Text, False); if StructuredLists[i].ChildCatalogs.Count > 0 then // Tolik 14/11/2020 -- исключить деление на НОЛЬ!!! CabDelta := MaketX / StructuredLists[i].ChildCatalogs.Count; // КАБИНЕТЫ for j := 0 to StructuredLists[i].ChildCatalogs.Count - 1 do begin ListCatalog := StructuredLists[i].ChildCatalogs[j]; // ! New(ptrPlanCabinet); ptrPlanCabinet.FSizeX := CabDelta; ptrPlanCabinet.FSizeY := FloorDelta; ptrPlanCabinet.FBounds.Left := BegPosX; ptrPlanCabinet.FBounds.Right := BegPosX + ptrPlanCabinet.FSizeX; ptrPlanCabinet.FBounds.Top := BegPosY; ptrPlanCabinet.FBounds.Bottom := BegPosY + ptrPlanCabinet.FSizeY; ptrPlanCabinet.FObjects := TList.Create; // ! BegPosX := BegPosX + CabDelta; if j < StructuredLists[i].ChildCatalogs.Count - 1 then begin // линию разделительную Line := TLine.Create(BegPosX, BegPosY, BegPosX, BegPosY + FloorDelta, 1, ord(psDash), clBlack, 0, LHandle, mydsNormal, aList.PCad); aList.PCad.AddCustomFigure(1, Line, False); end; CabBound.Top := BegPosY; CabBound.Bottom := BegPosY + FloorDelta; CabBound.Left := BegPosX - CabDelta; CabBound.Right := BegPosX; // нарисовать номер кабинета CabCenter.x := (CabBound.Right + CabBound.Left) / 2; CabCenter.y := (CabBound.Bottom + CabBound.Top) / 2; NbrCircle := TCircle.Create(CabCenter.x, CabCenter.y, 6, 1, ord(psDash), clMaroon, ord(bsClear), clNone, LHandle, mydsNormal, aList.PCad); aList.PCad.AddCustomFigure(1, NbrCircle, False); NbrText := TText.Create(CabCenter.x - 1.5, CabCenter.y - 3, 6, 3, IntToStr(ListCatalog.MarkID), aList.FFontName, RUSSIAN_CHARSET, clMaroon, LHandle, mydsNormal, aList.PCad); aList.PCad.AddCustomFigure(1, NbrText, False); // ОБЪЕКТЫ ПО ТИПАМ for k := 0 to StructuredLists[i].ChildCatalogs[j].ChildCatalogs.Count - 1 do begin ObjGroup := DrawObjectsOnProjectPlan(aList, StructuredLists[i].ChildCatalogs[j].ChildCatalogs[k], CabBound, MaxX, MaxY); if k = 0 then ObjGroup.move(0, 0) else if k = 1 then ObjGroup.move(CabDelta / 2, 0) else if k = 2 then ObjGroup.move(0, FloorDelta / 2) else if k = 3 then ObjGroup.move(CabDelta / 2, FloorDelta / 2) else ObjGroup.move(CabDelta / 2, FloorDelta / 2); ObjGroup.FSCSID := StructuredLists[i].ChildCatalogs[j].ChildCatalogs[k].SCSID; ObjGroup.FFloorNumber := i; ObjGroup.FCabNumber := j; ptrPlanCabinet.FObjects.Add(ObjGroup); end; ptrPlanFloor.FCabinets.Add(ptrPlanCabinet); end; ptrPlanProject.FFloors.Add(ptrPlanFloor); end; ObjList := TObjectList(CurrProject.GetPlanJoining(StructuredLists)); // ПРОВЕСТИ ТРАССЫ DrawTracesOnProjectPlan(aList, ptrPlanProject, ObjList); // Tolik -- 09/03/2017 -- утечка памяти -- нужно освободить занятую память !!! {for i := 0 to ObjList.Count - 1 do begin ConnectionsGroup := TCatalogGroupConnection(ObjList[i]); ConnectionsGroup.Free; end;} { for i := (ObjList.Count - 1) downto 0 do begin ConnectionsGroup := TCatalogGroupConnection(ObjList[i]); ObjList.Remove(ConnectionsGroup); ConnectionsGroup.Free; end; } ObjList.Clear; ObjList.Free; // -- объекты // структура проекта for i := 0 to ptrPlanProject.FFloors.Count - 1 do begin ptrPlanFloor := ptrPlanProject.FFloors[i]; for j := 0 to ptrPlanFloor.FCabinets.Count - 1 do begin ptrPlanCabinet := ptrPlanFloor.FCabinets[j]; ptrPlanCabinet.FObjects.Clear; FreeAndNil(ptrPlanCabinet.FObjects); FreeMem(ptrPlanCabinet); end; ptrPlanFloor.FCabinets.clear; FreeAndNil(ptrPlanFloor.FCabinets); FreeMem(ptrPlanFloor); end; ptrPlanProject.FFloors.Clear; FreeAndNil(ptrPlanProject.FFloors); FreeMem(ptrPlanProject); // FreeAndNil(StructuredLists); RefreshCAD(aList.PCad); aList.CurrentLayer := 1; except on E: Exception do AddExceptionToLogEx('U_ProjectPlan.UpdateProjectPlan', E.Message); end; EndProgress; end; function DrawObjectsOnProjectPlan(aList: TF_CAD; aObjCatalog: TSCSCatalog; aCabBounds: TDoubleRect; aObjectX, aObjectY: Double): TPlanObject; var i, j, k: Integer; Stream: TMemoryStream; NotesList: TStringList; GroupName: String; GroupCount: Integer; LHandle: Integer; TotalFigure: TPlanObject; Block: TBlock; Rect: TRectangle; BlockBnd: TDoubleRect; BlockX, BlockY: double; NoteBnd: TDoubleRect; NoteX, NoteY: double; ScaleDelta: Double; NotesGroup: TRichText; TM: TTextMetric; xCanvas: TMetafileCanvas; h, w: double; BlockCP: TDoublePoint; NeedCP: TDoublePoint; begin try Result := nil; LHandle := aList.PCad.GetLayerHandle(1); Stream := aObjCatalog.GetObjectIcon(ieBlk); GroupName := aObjCatalog.Name; NotesList := aObjCatalog.Notes; GroupCount := aObjCatalog.ChildCatalogs.Count; if Stream <> nil then begin Block := TBlock(aList.PCad.InsertBlockFromStream(1, Stream, -100, -100)); end else begin Rect := TRectangle.create(-100, -100, -100 + 18, -100 + 12, 2, ord(psSolid), clBlack, ord(bsClear), clNone, LHandle, mydsNormal, aList.PCad); Block := TBlock.Create(LHandle, aList.PCad); Block.AddFigure(Rect); aList.PCad.AddCustomFigure(1, Block, False); end; // масштабирование УО BlockBnd := Block.GetBoundRect; BlockX := abs(BlockBnd.Left - BlockBnd.Right); BlockY := abs(BlockBnd.Top - BlockBnd.Bottom); ScaleDelta := GetBlockScale(Block, aObjectX, aObjectY); Block.Scale(ScaleDelta, ScaleDelta); RefreshCAD(aList.PCad); BlockBnd := Block.GetBoundRect; BlockX := abs(BlockBnd.Left - BlockBnd.Right); BlockY := abs(BlockBnd.Top - BlockBnd.Bottom); {==========================================================================} for k := 14 downto 1 do begin NotesGroup := TRichText.create(-100, -100, -100, -100, 1, ord(psSolid), clBlue, ord(bsClear), clBlack, LHandle, mydsNormal, aList.PCad); NotesGroup.re.Font.Size := k; NotesGroup.RE.Lines.Clear; for i := 0 to NotesList.Count - 1 do begin NotesList[i] := FastReplace(NotesList[i],#13#10,' '); NotesGroup.re.Lines.Add(NotesList[i]); end; aList.PCad.AddCustomFigure(1, NotesGroup, False); RefreshCAD(aList.PCad); // получить свойства // Tolik NotesGroup.ttMetaFile:= TMetaFile.Create; NotesGroup.ttMetafile.Enhanced := True; xCanvas := TMetafileCanvas.Create(NotesGroup.ttMetafile, 0); xCanvas.Font.Name := NotesGroup.re.Font.Name; xCanvas.Font.Size := NotesGroup.re.Font.Size; GetTextMetrics(xCanvas.Handle, TM); h := TM.tmHeight / 4 * NotesGroup.re.Lines.Count + 1; w := 0; for i := 0 to NotesGroup.re.Lines.Count - 1 do begin if w < xCanvas.TextWidth(NotesGroup.Re.Lines[i]) then w := xCanvas.TextWidth(NotesGroup.Re.Lines[i]); end; w := (w + 3) / 4 ; FreeAndNil(xCanvas); NotesGroup.ttMetaFile.Free; // пересоздать с новыми свойствами if NotesGroup <> nil then begin aList.PCad.Figures.Remove(NotesGroup); FreeAndNil(NotesGroup); end; if (k = 1) or (w < BlockX) and (h < BlockY) then begin NotesGroup := TRichText.create(-100, -100, -100 + w, -100 + h, 1, ord(psSolid), clBlue, ord(bsClear), clBlack, LHandle, mydsNormal, aList.PCad); NotesGroup.re.Font.Size := k; NotesGroup.RE.Lines.Clear; for i := 0 to NotesList.Count - 1 do begin NotesList[i] := FastReplace(NotesList[i],#13#10,' '); NotesGroup.re.Lines.Add(NotesList[i]); end; RefreshCAD(aList.PCad); Break; end; end; {==========================================================================} // подгонка подписи под УО BlockBnd := Block.GetBoundRect; BlockCP.x := BlockBnd.Left + BlockX / 2; BlockCP.y := BlockBnd.Top + BlockY / 2; NotesGroup.Move(BlockCP.x - NotesGroup.CenterPoint.x, BlockCP.y - NotesGroup.CenterPoint.y); // в общий объект TotalFigure := TPlanObject.create(LHandle, aList.PCad); TotalFigure.AddFigure(Block); TotalFigure.AddFigure(NotesGroup); Result := TPlanObject(aList.PCad.AddCustomFigure(1, TotalFigure, False)); if Block <> nil then aList.PCad.Figures.Remove(Block); // смещение Result объекта BlockBnd := Result.GetBoundRect; BlockX := abs(BlockBnd.Left - BlockBnd.Right); BlockY := abs(BlockBnd.Top - BlockBnd.Bottom); Result.FSizeX := BlockX; Result.FSizeY := BlockY; Result.Deselect; Result.move(aCabBounds.Left - Result.CenterPoint.x + BlockX / 2 + 2, aCabBounds.Top - Result.CenterPoint.y + BlockY / 2 + 2); NeedCP := GetCoordsWithSnapToGrid(Result.CenterPoint.x, Result.CenterPoint.y); Result.move(NeedCP.x - Result.CenterPoint.x, NeedCP.y - Result.CenterPoint.y); RefreshCAD(aList.PCad); FreeAndNil(Stream); except on E: Exception do AddExceptionToLogEx('U_ProjectPlan.DrawObjectsOnProjectPlan', E.Message); end; end; procedure DrawTracesOnProjectPlan(aList: TF_CAD; aPlanProject: PPlanProject; aObjList: TObjectList); var i: integer; aConnectionsGroup: TCatalogGroupConnection; BegCatalog: TSCSCatalog; EndCatalog: TSCSCatalog; Lines: TSCSCatalogs; BegObject: TPlanObject; EndObject: TPlanObject; LinesNotes: TStringList; BegObjectType, EndObjectType: string; begin try for i := 0 to aObjList.Count - 1 do begin aConnectionsGroup := TCatalogGroupConnection(aObjList[i]); BegCatalog := aConnectionsGroup.BeginCatalogGroup; EndCatalog := aConnectionsGroup.EndCatalogGroup; LinesNotes := aConnectionsGroup.LinesNote; BegObject := FindPlanObject(aList, BegCatalog.SCSID); EndObject := FindPlanObject(aList, EndCatalog.SCSID); BegObjectType := BegCatalog.GUIDComponentType; EndObjectType := EndCatalog.GUIDComponentType; if (BegObject <> nil) and (EndObject <> nil) then DrawTraceWay(aList, aPlanProject, BegObject, EndObject, LinesNotes, BegObjectType, EndObjectType); end; except on E: Exception do AddExceptionToLogEx('U_ProjectPlan.DrawTracesOnProjectPlan', E.Message); end; end; procedure DrawTraceWay(aList: TF_CAD; aPlanProject: PPlanProject; aBegObject, aEndObject: TPlanObject; aLinesNotes: TStringList; aBegObjectType, aEndObjectType: string); var i, j, k: Integer; x1, x2, y1, y2: Double; PlanTrace1, PlanTrace2, PlanTrace3: TPlanTrace; Conn1, Conn2, Conn3, Conn4: TPlanConnector; LHandle: Integer; CabBounds: TDoubleRect; CabPosX: Double; deltato: Double; begin try CabBounds := PPlanCabinet(PPlanFloor(aPlanProject.FFloors[aBegObject.FFloorNumber]).FCabinets[aBegObject.FCabNumber]).FBounds; CabPosX := abs(CabBounds.Right - CabBounds.Left) / 2; CabPosX := CabPosX + abs(CabBounds.Right - CabBounds.Left) * aBegObject.FCabNumber + aPlanProject.FBounds.Left; LHandle := aList.PCad.GetLayerHandle(1); // Correct BeginEnd Objects Pos if aBegObject.FFloorNumber = aEndObject.FFloorNumber then if abs(aBegObject.CenterPoint.y - aEndObject.CenterPoint.y) < 1 then aBegObject.move(0, 1); // начинать вправо if aBegObject.CenterPoint.x < CabPosX then begin x1 := aBegObject.CenterPoint.x + aBegObject.FSizeX / 2; y1 := aBegObject.CenterPoint.y; x2 := CabPosX; y2 := y1; if abs(x1 - x2) < 5 then begin if x1 < x2 then x2 := x1 + 5 else x2 := x1 - 5; end; end else // влево begin x1 := aBegObject.CenterPoint.x - aBegObject.FSizeX / 2; y1 := aBegObject.CenterPoint.y; x2 := CabPosX; y2 := y1; if abs(x1 - x2) < 5 then begin if x1 < x2 then x2 := x1 + 5 else x2 := x1 - 5; end; end; x1 := GetCoordXWithSnapToGrid(x1); y1 := GetCoordXWithSnapToGrid(y1); x2 := GetCoordXWithSnapToGrid(x2); y2 := GetCoordXWithSnapToGrid(y2); // Connector1 Conn1 := TPlanConnector.Create(x1, y1, 0, LHandle, mydsNormal, aList.PCad); Conn1.FBegSCSID := aBegObject.FSCSID; Conn1.FEndSCSID := aEndObject.FSCSID; Conn1.FBegType := aBegObjectType; Conn1.FEndType := aEndObjectType; Conn1.ConnectorType := ct_Clear; aList.PCad.AddCustomFigure (1, Conn1, False); // DELETE FROM PM // if Conn1.Selected then // Conn1.Deselect; // DeleteObjectFromPM(Conn1.ID, Conn1.Name); aBegObject.JoinedConnectors.Add(Conn1); Conn1.JoinedPlanObject := aBegObject; Conn1.LockSelect := True; Conn1.LockModify := True; // Trace1 PlanTrace1 := TPlanTrace.create(x1, y1, x2, y2, 2, ord(psSolid), clNavy, 0, LHandle, mydsNormal, aList.PCad); PlanTrace1.FBegSCSID := aBegObject.FSCSID; PlanTrace1.FEndSCSID := aEndObject.FSCSID; PlanTrace1.FBegType := aBegObjectType; PlanTrace1.FEndType := aEndObjectType; aList.PCad.AddCustomFigure(1, PlanTrace1, False); // Connector2 Conn2 := TPlanConnector.Create(x2, y2, 0, LHandle, mydsNormal, aList.PCad); Conn2.FBegSCSID := aBegObject.FSCSID; Conn2.FEndSCSID := aEndObject.FSCSID; Conn2.FBegType := aBegObjectType; Conn2.FEndType := aEndObjectType; Conn2.ConnectorType := ct_Clear; aList.PCad.AddCustomFigure (1, Conn2, False); // DELETE FROM PM // if Conn2.Selected then // Conn2.Deselect; // DeleteObjectFromPM(Conn2.ID, Conn1.Name); PlanTrace1.SetJConnector1(Conn1); SetConnBringToFront(Conn1); PlanTrace1.SetJConnector2(Conn2); CreatePlanTraceCaption(PlanTrace1, aLinesNotes); // FindSnapLine if aBegObjectType <> aEndObjectType then begin if FindSnapOnTraceTraffic(PlanTrace1, aEndObject, aBegObjectType, aEndObjectType) then Exit; end; // если в точке начала - спустить на 1 while CheckPlanConnectorAtPos(Conn1, Conn1.ActualPoints[1].x, Conn1.ActualPoints[1].y) do begin if Conn1 <> nil then Conn1.move(0, 3); if Conn2 <> nil then Conn2.move(0, 3); // PlanTrace1.Move(0, 3); end; // Trace2 x1 := Conn2.ActualPoints[1].x; y1 := Conn2.ActualPoints[1].y; x2 := x1; y2 := aEndObject.CenterPoint.y; x2 := GetCoordXWithSnapToGrid(x2); y2 := GetCoordXWithSnapToGrid(y2); if abs(y1 - y2) < 1 then y2 := y1 + 1; PlanTrace2 := TPlanTrace.create(x1, y1, x2, y2, 2, ord(psSolid), clNavy, 0, LHandle, mydsNormal, aList.PCad); PlanTrace2.FBegSCSID := aBegObject.FSCSID; PlanTrace2.FEndSCSID := aEndObject.FSCSID; PlanTrace2.FBegType := aBegObjectType; PlanTrace2.FEndType := aEndObjectType; aList.PCad.AddCustomFigure (1, PlanTrace2, False); // Connector3 Conn3 := TPlanConnector.Create(x2, y2, 0, LHandle, mydsNormal, aList.PCad); Conn3.FBegSCSID := aBegObject.FSCSID; Conn3.FEndSCSID := aEndObject.FSCSID; Conn3.FBegType := aBegObjectType; Conn3.FEndType := aEndObjectType; Conn3.ConnectorType := ct_Clear; aList.PCad.AddCustomFigure (1, Conn3, False); // DELETE FROM PM // if Conn3.Selected then // Conn3.Deselect; // DeleteObjectFromPM(Conn3.ID, Conn1.Name); PlanTrace2.SetJConnector1(Conn2); SetConnBringToFront(Conn2); PlanTrace2.SetJConnector2(Conn3); // LineCorrect if (aEndObject.IsPointIn(Conn2.ActualPoints[1].x, Conn2.ActualPoints[1].y)) or (aEndObject.IsPointIn(Conn3.ActualPoints[1].x, Conn3.ActualPoints[1].y)) then begin if PlanTrace1.ActualPoints[1].x < PlanTrace1.ActualPoints[2].x then begin deltato := aEndObject.CenterPoint.x + aEndObject.FSizeX / 2 + 5; deltato := GetCoordXWithSnapToGrid(deltato); PlanTrace2.Move(deltato - Conn3.ActualPoints[1].x, 0); end else begin deltato := aEndObject.CenterPoint.x - aEndObject.FSizeX / 2 + 5; deltato := GetCoordXWithSnapToGrid(deltato); PlanTrace2.Move(deltato - Conn3.ActualPoints[1].x, 0); end; end; // FindSnapLine if aBegObjectType <> aEndObjectType then begin if FindSnapOnTraceTraffic(PlanTrace2, aEndObject, aBegObjectType, aEndObjectType) then Exit; end; // Trace3 CabPosX := Conn3.ActualPoints[1].x; // налево if aEndObject.CenterPoint.x < CabPosX then begin x1 := Conn3.ActualPoints[1].x; y1 := Conn3.ActualPoints[1].y; x2 := aEndObject.CenterPoint.x + aEndObject.FSizeX / 2; y2 := y1; end else // направо begin x1 := Conn3.ActualPoints[1].x; y1 := Conn3.ActualPoints[1].y; x2 := aEndObject.CenterPoint.x - aEndObject.FSizeX / 2; y2 := y1; end; PlanTrace3 := TPlanTrace.create(x1, y1, x2, y2, 2, ord(psSolid), clNavy, 0, LHandle, mydsNormal, aList.PCad); PlanTrace3.FBegSCSID := aBegObject.FSCSID; PlanTrace3.FEndSCSID := aEndObject.FSCSID; PlanTrace3.FBegType := aBegObjectType; PlanTrace3.FEndType := aEndObjectType; aList.PCad.AddCustomFigure (1, PlanTrace3, False); // Connector4 Conn4 := TPlanConnector.Create(x2, y2, 0, LHandle, mydsNormal, aList.PCad); Conn4.FBegSCSID := aBegObject.FSCSID; Conn4.FEndSCSID := aEndObject.FSCSID; Conn4.FBegType := aBegObjectType; Conn4.FEndType := aEndObjectType; Conn4.ConnectorType := ct_Clear; aList.PCad.AddCustomFigure (1, Conn4, False); // DELETE FROM PM // if Conn4.Selected then // Conn4.Deselect; // DeleteObjectFromPM(Conn4.ID, Conn4.Name); PlanTrace3.SetJConnector1(Conn3); SetConnBringToFront(Conn3); PlanTrace3.SetJConnector2(Conn4); SetConnBringToFront(Conn4); // LineCorrect if aBegObjectType <> aEndObjectType then begin if FindSnapOnTraceTraffic(PlanTrace3, aEndObject, aBegObjectType, aEndObjectType) then Exit; end; // если в точке конца трассы - спустить на 1 while CheckPlanConnectorAtPos(Conn4, Conn4.ActualPoints[1].x, Conn4.ActualPoints[1].y) do begin if Conn3 <> nil then Conn3.move(0, 3); if Conn4 <> nil then Conn4.move(0, 3); // PlanTrace3.Move(0, 3); end; aEndObject.JoinedConnectors.Add(Conn4); Conn4.JoinedPlanObject := aEndObject; Conn4.LockSelect := True; Conn4.LockModify := True; except on E: Exception do AddExceptionToLogEx('U_ProjectPlan.DrawTraceWay', E.Message); end; end; function FindPlanObject(aList: TF_CAD; aSCSID: Integer): TPlanObject; var i: integer; begin try Result := nil; for i := 0 to aList.PCad.FigureCount - 1 do begin if CheckFigureByClassName(TFigure(aList.PCad.Figures[i]), cTPlanObject) then begin if TPlanObject(aList.PCad.Figures[i]).FSCSID = aSCSID then Result := TPlanObject(aList.PCad.Figures[i]); end; end; except on E: Exception do AddExceptionToLogEx('U_ProjectPlan.FindPlanObject', E.Message); end; end; function GetListBound(aList: TF_CAD): TDoubleRect; var ListWidth, Listheight: double; ListBottomParam: double; step: double; LeftBound, RightBound, TopBound, BottomBound: double; begin try Result := DoubleRect(0, 0, 0, 0); ListWidth := AList.PCad.WorkWidth; ListHeight := AList.PCad.WorkHeight; if AList.FCadStampType = stt_simple then ListBottomParam := 15 else if AList.FCadStampType = stt_extended then ListBottomParam := 40 else if AList.FCadStampType = stt_detailed then ListBottomParam := 55; step := aList.PCad.GridStep; TopBound := 25; LeftBound := 30; RightBound := aList.PCad.WorkWidth - 15; BottomBound := aList.PCad.WorkHeight - 20 - ListBottomParam; Result.Top := GetCoordYWithSnapToGrid(TopBound); Result.Left := GetCoordXWithSnapToGrid(LeftBound); Result.Right := GetCoordYWithSnapToGrid(RightBound); Result.Bottom := GetCoordYWithSnapToGrid(BottomBound); except on E: Exception do AddExceptionToLogEx('U_ProjectPlan.GetListBound', E.Message); end; end; function GetBlockScale(aObject: TFigureGrp; aX, aY: double): Double; var BlockBnd: TDoubleRect; BlockX, BlockY: double; CabX, CabY: Double; px, py: double; begin try Result := 0; BlockBnd := aObject.GetBoundRect; BlockX := abs(BlockBnd.Left - BlockBnd.Right); BlockY := abs(BlockBnd.Top - BlockBnd.Bottom); CabX := aX; CabY := aY; px := (CabX - 6) / BlockX / 2; py := (CabY - 6) / BlockY / 2; if px < py then Result := px else Result := py; except on E: Exception do AddExceptionToLogEx('U_ProjectPlan.GetBlockScale', E.Message); end; end; function GetScaleNotesToBlock(aBlockBnd, aNoteBnd: TDoubleRect): Double; var BlockX, BlockY: double; NoteX, NoteY: double; LimitNoteX, LimitNoteY: double; KoefScaleX, KoefScaleY: double; begin try Result := 0; BlockX := abs(aBlockBnd.Left - aBlockBnd.Right); BlockY := abs(aBlockBnd.Top - aBlockBnd.Bottom); NoteX := abs(aNoteBnd.Left - aNoteBnd.Right); NoteY := abs(aNoteBnd.Top - aNoteBnd.Bottom); LimitNoteX := BlockX - 2; LimitNoteY := BlockY - 2; KoefScaleX := LimitNoteX / NoteX; KoefScaleY := LimitNoteY / NoteY; if KoefScaleX < KoefScaleY then Result := KoefScaleX else Result := KoefScaleY; except on E: Exception do AddExceptionToLogEx('U_ProjectPlan.ScaleNotesToBlock', E.Message); end; end; function CheckByPlanTrace(aX, aY: Double; aTracesList: TList): TPlanTrace; var i: integer; CurFigure: TFigure; begin try Result := nil; for i := 0 to GCadForm.PCad.FigureCount - 1 do begin CurFigure := TFigure(GCadForm.PCad.Figures[i]); if CheckFigureByClassName(CurFigure, cTPlanTrace) then begin if CheckNoFigureInList(CurFigure, aTracesList) then if TPlanTrace(CurFigure).IsPointIn(aX, aY) then Result := TPlanTrace(CurFigure); end; end; except on E: Exception do AddExceptionToLogEx('U_ProjectPlan.CheckByPlanTrace', E.Message); end; end; function CheckByPlanConnector(aX, aY: Double; aCurrConn1, aCurrConn2: TPlanConnector): TPlanConnector; var i: integer; CurFigure: TFigure; begin try Result := nil; for i := 0 to GCadForm.PCad.FigureCount - 1 do begin CurFigure := TFigure(GCadForm.PCad.Figures[i]); if CheckFigureByClassName(CurFigure, cTPlanConnector) then begin if TPlanConnector(CurFigure).IsPointIn(aX, aY) then if (aCurrConn1 <> TPlanConnector(CurFigure)) and (aCurrConn2 <> TPlanConnector(CurFigure)) then if TPlanConnector(CurFigure).JoinedPlanObject = nil then Result := TPlanConnector(CurFigure); end; end; except on E: Exception do AddExceptionToLogEx('U_ProjectPlan.CheckByPlanConnector', E.Message); end; end; function CheckPlanConnectorAtPos(aSelf: TPlanConnector; aX, aY: Double): Boolean; var i: Integer; CurFigure: TFigure; begin try Result := false; for i := 0 to GCadForm.PCad.FigureCount - 1 do begin CurFigure := TFigure(GCadForm.PCad.Figures[i]); if CheckFigureByClassName(CurFigure, cTPlanConnector) then begin if TPlanConnector(CurFigure) <> aSelf then if TPlanConnector(CurFigure).IsPointIn(aX, aY) then if TPlanConnector(CurFigure).JoinedPlanObject <> nil then Result := True; end; end; except on E: Exception do AddExceptionToLogEx('U_ProjectPlan.CheckPlanConnectorAtPos', E.Message); end; end; function CheckTypesIdentity(aCurrBegType, aCurrEndType, aSnapBegType, aSnapEndType: string): Boolean; begin try Result := false; if ((aCurrBegType = aSnapBegType) and (aCurrEndType = aSnapEndType)) or ((aCurrBegType = aSnapEndType) and (aCurrEndType = aSnapBegType)) then Result := True; except on E: Exception do AddExceptionToLogEx('U_ProjectPlan.CheckTypesIdentity', E.Message); end; end; function CheckPlanConnectorGoesToEndObject(aEndSCSID: Integer; aPlanConnector: TPlanConnector): Boolean; var i: integer; CurTrace: TPlanTrace; begin try Result := false; if aEndSCSID = aPlanConnector.FEndSCSID then Result := true else Result := false; except on E: Exception do AddExceptionToLogEx('U_ProjectPlan.CheckPlanConnectorGoesToEndObject', E.Message); end; end; function CheckPlanTraceGoesToEndObject(aEndSCSID: Integer; aPlanTrace: TPlanTrace): Boolean; begin try Result := false; if aEndSCSID = aPlanTrace.FEndSCSID then Result := true else Result := false; except on E: Exception do AddExceptionToLogEx('U_ProjectPlan.CheckPlanTraceGoesToEndObject', E.Message); end; end; procedure SnapToPlanConnector(aConnector, aSnapConnector: TPlanConnector); var i, j: integer; NewDeltaX, NewDeltaY: double; OLine: TPlanTrace; begin try aConnector.Name := aSnapConnector.Name; // вычисление разницы в координатах для соединения обьектов NewDeltaX := ASnapConnector.ActualPoints[1].x - AConnector.ActualPoints[1].x; NewDeltaY := ASnapConnector.ActualPoints[1].y - AConnector.ActualPoints[1].y; AConnector.ActualPoints[1] := DoublePoint(ASnapConnector.ActualPoints[1].x, ASnapConnector.ActualPoints[1].y); for i := 0 to AConnector.JoinedTraces.Count - 1 do begin if AConnector = TPlanTrace(AConnector.JoinedTraces[i]).JoinObject1 then begin TPlanTrace(AConnector.JoinedTraces[i]).ActualPoints[1] := DoublePoint( TPlanTrace(AConnector.JoinedTraces[i]).ActualPoints[1].x + NewDeltaX, TPlanTrace(AConnector.JoinedTraces[i]).ActualPoints[1].y + NewDeltaY); end; if AConnector = TPlanTrace(AConnector.JoinedTraces[i]).JoinObject2 then begin TPlanTrace(AConnector.JoinedTraces[i]).ActualPoints[2] := DoublePoint( TPlanTrace(AConnector.JoinedTraces[i]).ActualPoints[2].x + NewDeltaX, TPlanTrace(AConnector.JoinedTraces[i]).ActualPoints[2].y + NewDeltaY); end; end; for i := 0 to ASnapConnector.JoinedTraces.Count - 1 do begin OLine := TPlanTrace(ASnapConnector.JoinedTraces[i]); if OLine.JoinObject1 = ASnapConnector then begin OLine.SetJConnector1(AConnector); end; if OLine.JoinObject2 = ASnapConnector then begin OLine.SetJConnector2(AConnector); end; end; aSnapConnector.JoinedTraces.Clear; aSnapConnector.Delete; RefreshCAD(GCadForm.PCad); except on E: Exception do AddExceptionToLogEx('U_ProjectPlan.SnapToPlanConnector', E.Message); end; end; procedure SnapToPlanTrace(aConnector: TPlanConnector; aSnapTrace: TPlanTrace); var i, j: integer; NewDeltaX, NewDeltaY: double; AddLine: TPlanTrace; NextConnector: TFigure; Modx, Mody, NextModx, NextMody: Double; DeltaHeight: Double; JoinedConn: TPlanConnector; begin try NextConnector := aSnapTrace.JoinObject2; if aSnapTrace.ActualPoints[1].x = aSnapTrace.ActualPoints[2].x then begin NewDeltaY := 0; NewDeltaX := aSnapTrace.ActualPoints[1].x - AConnector.ActualPoints[1].x; AConnector.ActualPoints[1] := DoublePoint(AConnector.ActualPoints[1].x + NewDeltaX, AConnector.ActualPoints[1].y); end else if aSnapTrace.ActualPoints[1].y = aSnapTrace.ActualPoints[2].y then begin NewDeltaX := 0; NewDeltaY := aSnapTrace.ActualPoints[1].y - AConnector.ActualPoints[1].y; AConnector.ActualPoints[1] := DoublePoint(AConnector.ActualPoints[1].x, AConnector.ActualPoints[1].y + NewDeltaY); end else begin NewDeltaX := 0; NewDeltaY := 0; AConnector.ActualPoints[1] := DoublePoint(AConnector.ActualPoints[1].x + NewDeltaX, AConnector.ActualPoints[1].y + NewDeltaY); end; for i := 0 to AConnector.JoinedTraces.Count - 1 do begin if AConnector = TPlanTrace(AConnector.JoinedTraces[i]).JoinObject1 then begin TPlanTrace(AConnector.JoinedTraces[i]).ActualPoints[1] := DoublePoint( TPlanTrace(AConnector.JoinedTraces[i]).ActualPoints[1].x + NewDeltaX, TPlanTrace(AConnector.JoinedTraces[i]).ActualPoints[1].y + NewDeltaY); end; if AConnector = TPlanTrace(AConnector.JoinedTraces[i]).JoinObject2 then begin TPlanTrace(AConnector.JoinedTraces[i]).ActualPoints[2] := DoublePoint( TPlanTrace(AConnector.JoinedTraces[i]).ActualPoints[2].x + NewDeltaX, TPlanTrace(AConnector.JoinedTraces[i]).ActualPoints[2].y + NewDeltaY); end; end; // вычисление точек модификации Modx := (AConnector.ActualPoints[1].x + AConnector.ActualPoints[2].x) / 2; Mody := (AConnector.ActualPoints[1].y + AConnector.ActualPoints[2].y) / 2; NextModx := (NextConnector.ActualPoints[1].x + NextConnector.ActualPoints[2].x) / 2; NextMody := (NextConnector.ActualPoints[1].y + NextConnector.ActualPoints[2].y) / 2; // При соединении конектора с линией, создается 2 линии // переназначение связей линии к которой присоединились новому коннектору aSnapTrace.ActualPoints[2] := DoublePoint(Modx, Mody); aSnapTrace.SetJConnector2(AConnector); TPlanConnector(NextConnector).JoinedTraces.Remove(aSnapTrace); AddLine := TPlanTrace.Create(Modx, Mody, NextModx, NextMody, aSnapTrace.width, ord(aSnapTrace.Style), aSnapTrace.Color, 0, aSnapTrace.LayerHandle, mydsNormal, GCadForm.PCad); GCadForm.PCad.AddCustomFigure (GLN(aSnapTrace.LayerHandle), AddLine, false); // присвоить связи новой ортолинии AddLine.SetJConnector1(AConnector); AddLine.SetJConnector2(NextConnector); SetConnBringToFront(AConnector); AddLine.FBegSCSID := aSnapTrace.FBegSCSID; AddLine.FEndSCSID := aSnapTrace.FEndSCSID; RefreshCAD(GCadForm.PCad); except on E: Exception do AddExceptionToLogEx('U_ProjectPlan.SnapToPlanTrace', E.Message); end; end; function FindSnapOnTraceTraffic(aPlanTrace: TPlanTrace; aEndObject: TPlanObject; aBegObjectType, aEndObjectType: string): Boolean; var i: integer; CheckConnector: TPlanConnector; CheckTrace: TPlanTrace; Conn1, Conn2: TPlanConnector; CheckedX, CheckedY: double; x1, x2, y1, y2: double; step: double; TracesList: TList; begin try Result := false; TracesList := TList.create; Conn1 := TPlanConnector(aPlanTrace.JoinObject1); Conn2 := TPlanConnector(aPlanTrace.JoinObject2); for i := 0 to Conn1.JoinedTraces.Count - 1 do TracesList.Add(Conn1.JoinedTraces[i]); for i := 0 to Conn2.JoinedTraces.Count - 1 do TracesList.Add(Conn2.JoinedTraces[i]); // CHECK BY SNAP !!! step := GCadForm.PCad.GridStep; CheckedX := Conn2.ActualPoints[1].x; CheckedY := Conn2.ActualPoints[1].y; // по X if abs(aPlanTrace.ActualPoints[1].y - aPlanTrace.ActualPoints[2].y) < 0.1 then begin x1 := aPlanTrace.ActualPoints[1].x; x2 := aPlanTrace.ActualPoints[2].x; // путь идет вправо if aPlanTrace.ActualPoints[1].x < aPlanTrace.ActualPoints[2].x then begin while x1 <= x2 do begin CheckConnector := CheckByPlanConnector(x1, CheckedY, Conn1, Conn2); CheckTrace := CheckByPlanTrace(x1, CheckedY, TracesList); if CheckConnector <> nil then begin if CheckPlanConnectorGoesToEndObject(aEndObject.FSCSID, CheckConnector) then begin if CheckTypesIdentity(aBegObjectType, aEndObjectType, CheckConnector.FBegType, CheckConnector.FEndType) then begin Conn2.move(x1 - Conn2.ActualPoints[1].x, 0); SnapToPlanConnector(Conn2, CheckConnector); Result := true; // Tolik -- 09/03/2017 -- утечка памяти TracesList.Free; // exit; end; end; end else if CheckTrace <> nil then begin if CheckPlanTraceGoesToEndObject(aEndObject.FSCSID, CheckTrace) then begin if CheckTypesIdentity(aBegObjectType, aEndObjectType, CheckTrace.FBegType, CheckTrace.FEndType) then begin Conn2.move(x1 - Conn2.ActualPoints[1].x, 0); SnapToPlanTrace(Conn2, CheckTrace); Result := true; // Tolik -- 09/03/2017 -- утечка памяти TracesList.Free; // exit; end; end; end; x1 := x1 + step; end; end else // путь идет влево if aPlanTrace.ActualPoints[1].x > aPlanTrace.ActualPoints[2].x then begin while x1 >= x2 do begin CheckConnector := CheckByPlanConnector(x1, CheckedY, Conn1, Conn2); CheckTrace := CheckByPlanTrace(x1, CheckedY, TracesList); if CheckConnector <> nil then begin if CheckPlanConnectorGoesToEndObject(aEndObject.FSCSID, CheckConnector) then begin if CheckTypesIdentity(aBegObjectType, aEndObjectType, CheckConnector.FBegType, CheckConnector.FEndType) then begin Conn2.move(x1 - Conn2.ActualPoints[1].x, 0); SnapToPlanConnector(Conn2, CheckConnector); Result := true; // Tolik -- 09/03/2017 -- утечка памяти TracesList.Free; // exit; end; end; end else if CheckTrace <> nil then begin if CheckPlanTraceGoesToEndObject(aEndObject.FSCSID, CheckTrace) then begin if CheckTypesIdentity(aBegObjectType, aEndObjectType, CheckTrace.FBegType, CheckTrace.FEndType) then begin Conn2.move(x1 - Conn2.ActualPoints[1].x, 0); SnapToPlanTrace(Conn2, CheckTrace); Result := true; // Tolik -- 09/03/2017 -- утечка памяти TracesList.Free; // exit; end; end; end; x1 := x1 - step; end; end end else // по Y if abs(aPlanTrace.ActualPoints[1].x - aPlanTrace.ActualPoints[2].x) < 0.1 then begin y1 := aPlanTrace.ActualPoints[1].y; y2 := aPlanTrace.ActualPoints[2].y; // путь идет вниз if aPlanTrace.ActualPoints[1].y < aPlanTrace.ActualPoints[2].y then begin while y1 <= y2 do begin CheckConnector := CheckByPlanConnector(CheckedX, y1, Conn1, Conn2); CheckTrace := CheckByPlanTrace(CheckedX, y1, TracesList); if CheckConnector <> nil then begin if CheckPlanConnectorGoesToEndObject(aEndObject.FSCSID, CheckConnector) then begin if CheckTypesIdentity(aBegObjectType, aEndObjectType, CheckConnector.FBegType, CheckConnector.FEndType) then begin Conn2.move(0, y1 - Conn2.ActualPoints[1].y); SnapToPlanConnector(Conn2, CheckConnector); Result := true; // Tolik -- 09/03/2017 -- утечка памяти TracesList.Free; // exit; end; end; end else if CheckTrace <> nil then begin if CheckPlanTraceGoesToEndObject(aEndObject.FSCSID, CheckTrace) then begin if CheckTypesIdentity(aBegObjectType, aEndObjectType, CheckTrace.FBegType, CheckTrace.FEndType) then begin Conn2.move(0, y1 - Conn2.ActualPoints[1].y); SnapToPlanTrace(Conn2, CheckTrace); Result := true; // Tolik -- 09/03/2017 -- утечка памяти TracesList.Free; // exit; end; end; end; y1 := y1 + step; end; end else // путь идет вверх if aPlanTrace.ActualPoints[1].y > aPlanTrace.ActualPoints[2].y then begin while y1 >= y2 do begin CheckConnector := CheckByPlanConnector(CheckedX, y1, Conn1, Conn2); CheckTrace := CheckByPlanTrace(CheckedX, y1, TracesList); if CheckConnector <> nil then begin if CheckPlanConnectorGoesToEndObject(aEndObject.FSCSID, CheckConnector) then begin if CheckTypesIdentity(aBegObjectType, aEndObjectType, CheckConnector.FBegType, CheckConnector.FEndType) then begin Conn2.move(0, y1 - Conn2.ActualPoints[1].y); SnapToPlanConnector(Conn2, CheckConnector); Result := true; // Tolik -- 09/03/2017 -- утечка памяти TracesList.Free; // exit; end; end; end else if CheckTrace <> nil then begin if CheckPlanTraceGoesToEndObject(aEndObject.FSCSID, CheckTrace) then begin if CheckTypesIdentity(aBegObjectType, aEndObjectType, CheckTrace.FBegType, CheckTrace.FEndType) then begin Conn2.move(0, y1 - Conn2.ActualPoints[1].y); SnapToPlanTrace(Conn2, CheckTrace); Result := true; // Tolik -- 09/03/2017 -- утечка памяти TracesList.Free; // exit; end; end; end; y1 := y1 - step; end; end end except on E: Exception do AddExceptionToLogEx('U_ProjectPlan.FindSnapOnTraceTraffic', E.Message); end; end; procedure CreatePlanTraceCaption(aPlanTrace: TPlanTrace; aCaption: TStringList); var i: Integer; LHandle: Integer; NoteBnd: TDoubleRect; CaptionGroup: TRichText; TM: TTextMetric; xCanvas: TMetafileCanvas; h, w: double; TraceCP: TDoublePoint; MvAngle: Double; Bnd: TDoubleRect; begin try LHandle := GCadForm.PCad.GetLayerHandle(1); CaptionGroup := TRichText.create(-100, -100, -100, -100, 1, ord(aPlanTrace.Style), aPlanTrace.color, ord(bsClear), clNone, LHandle, mydsNormal, GCadForm.PCad); CaptionGroup.re.Font.Size := 6; CaptionGroup.re.Font.Color := aPlanTrace.color; CaptionGroup.re.Lines.Clear; for i := 0 to aCaption.Count - 1 do begin aCaption[i] := FastReplace(aCaption[i],#13#10,' '); CaptionGroup.re.Lines.Add(aCaption[i]); end; GCadForm.PCad.AddCustomFigure(1, CaptionGroup, False); RefreshCAD(GCadForm.PCad); // получить свойства // Tolik CaptionGroup.ttMetaFile:= TMetaFile.Create; CaptionGroup.ttMetafile.Enhanced := True; xCanvas := TMetafileCanvas.Create(CaptionGroup.ttMetafile, 0); xCanvas.Font.Name := CaptionGroup.re.Font.Name; xCanvas.Font.Size := CaptionGroup.re.Font.Size; GetTextMetrics(xCanvas.Handle, TM); h := TM.tmHeight / 4 * CaptionGroup.re.Lines.Count + 1; w := 0; for i := 0 to CaptionGroup.re.Lines.Count - 1 do begin if w < xCanvas.TextWidth(CaptionGroup.Re.Lines[i]) then w := xCanvas.TextWidth(CaptionGroup.Re.Lines[i]); end; w := (w + 3) / 4 ; FreeAndNil(xCanvas); CaptionGroup.ttMetaFile.Free; // пересоздать с новыми свойствами if CaptionGroup <> nil then begin GCadForm.PCad.Figures.Remove(CaptionGroup); FreeAndNil(CaptionGroup); end; CaptionGroup := TRichText.create(-100, -100, -100 + w, -100 + h, 1, ord(aPlanTrace.Style), aPlanTrace.color, ord(bsClear), clNone, LHandle, mydsNormal, GCadForm.PCad); CaptionGroup.re.Font.Size := 6; CaptionGroup.re.Font.Color := aPlanTrace.color; CaptionGroup.re.Lines.Clear; for i := 0 to aCaption.Count - 1 do begin aCaption[i] := FastReplace(aCaption[i],#13#10,' '); CaptionGroup.re.Lines.Add(aCaption[i]); end; TraceCP.x := (aPlanTrace.ActualPoints[1].x + aPlanTrace.ActualPoints[2].x) / 2; TraceCP.y := (aPlanTrace.ActualPoints[1].y + aPlanTrace.ActualPoints[2].y) / 2; CaptionGroup.Move(TraceCP.x - CaptionGroup.CenterPoint.x, TraceCP.y - CaptionGroup.CenterPoint.y); CaptionGroup.Move(0, - h / 2); MvAngle := GetPlanTraceAngle(aPlanTrace.ActualPoints[1], aPlanTrace.ActualPoints[2]); MvAngle := MvAngle * pi / 180; CaptionGroup.Rotate(MvAngle, CaptionGroup.CenterPoint); aPlanTrace.Caption := CaptionGroup; GCadForm.PCad.AddCustomFigure(1, aPlanTrace.Caption, False); RefreshCAD(GCadForm.PCad); except on E: Exception do AddExceptionToLogEx('U_ProjectPlan.CreatePlanTraceCaption', E.Message); end; end; function GetPlanTraceAngle(aPoints1, aPoints2: TDoublePoint): Double; var Len_X, Len_Y: Double; AngleA: Double; Degree: Double; begin try Result := 0; Degree := 0; Len_X := aPoints1.x - aPoints2.x; Len_Y := aPoints1.y - aPoints2.y; if Len_X = 0 then Len_X := 0.001; Degree := ArcTan(Len_Y / Len_X) * 180 / pi; // в градусах Degree := round(Degree); if Degree = 90 then Degree := -90; Result := Degree / 180 * pi; // в радианах except on E: Exception do AddExceptionToLogEx('U_ProjectPlan.GetPlanTraceAngle', E.Message); end; end; end.