unit U_ArchClasses; interface uses Forms, StdCtrls, SysUtils, Classes, ComCtrls, Windows, Controls, Contnrs, ExtCtrls, Messages, Dialogs, Math, TypInfo, U_Common_Classes, U_SCSComponent, U_SCSLists, U_BaseCommon, PCDrawing, DrawObjects, fplan, PCTypesUtils, PowerCad, U_BaseConstants, U_Constants; type TWallDivPath = class; TRoomWallRect = class; //TBrickWallRect = class; TWallPolyPath = class; TArchEngine = class; TArchExport = class; TWallDivPath = class(TWallPath) class function CreateFromShadow(aOwner: TComponent; LHandle: LongInt; Shadow: TFigure): TFigure; override; end; TRoomWallRect = class(TWallRect) class function CreateFromShadow(aOwner: TComponent; LHandle: LongInt; Shadow: TFigure): TFigure; override; end; //TBrickWallRect = class(TRoomWallRect) //end; TWallPolyPath = class(TPolyLine) class function CreateFromShadow(aOwner: TComponent; LHandle: Integer; Shadow: TFigure): TFigure;override; end; TArchEngine = class(TObject) private FCADToSetTool: TForm; FClassSetTool: TFigureClass; FToolData: LongInt; FInsertingObjectType: Integer; FInsertingObjectCount: Integer; FInsrtedPointsID: TIntList; FInsrtedCorners: TSCSComponents; FLookedPointsOnScale: TList; FLookedPointNetsOnScale: TList; FSavedLookedPointsOnScale: TList; FScaleObjectCount: Integer; FNetsToDefHeights: TList; FLastObjsSizes: TStringsHash; FTimerSetTool: TTimer; FTimerDefNetHeights: TTimer; function CreateTimer(AInterval: Integer; AOnTimer: TNotifyEvent): TTimer; procedure FOnTimer(Sender: TObject); procedure FOnTimerDefNetHeights(Sender: TObject); public FDeletingObject: TObject; FGroupingMode: Boolean; FIsExporting: Boolean; FExport: TArchExport; FPrevSelCADObj: TObject; FLastObjTiltAngle: Double; // Угол наклона объекта для которого подгружали переметры procedure BeginExport; procedure EndExport; procedure AfterLoadProps(AObject: TObject); function GetLastDoorObjSize(aDoorObjType: TDoorObjType; aDefVal: Double): Double; function GetLastObjSize(const aKey: String; aDefVal: Double): Double; // Tolik -- 09/11/2017 -- function GetLastObjParam(const aKey: String): boolean; // function OnAddPoint(Sender: TNet; aTrgPath: TNetPath; APoint: PDoublePoint; AID: Integer): Integer; procedure OnAfterDivPath(Sender: TObject); procedure OnAutoAddPath(Sender: TObject; SrcPath, NewPath: TNetPath); procedure OnBeforeDivPath(Sender: TObject); procedure OnDblClick(Sender: TObject); function OnDefineJoinedNets(Sender: TNet; ANetList, ACheckNetList, AResJoined: TList): Boolean; function OnDefineMoveObjects(Sender: TNet; Apt: PDoublePoint; APath: TNetPath; ANetList: TList; AllowNear: Boolean=true): Boolean; procedure OnDoorChangePathQuery(Sender: TNetDoor; APath, ANewPath: TNetPath; var CanChange: Boolean); procedure OnDeleteObj(Sender: TObject); function OnDeletePoint(Sender: TNet; APoint: PDoublePoint; AID: Integer): Integer; procedure OnDuplicate(SrcObj, NewObj: TObject); function OnGetHeight(Sender: TObject): Double; function OnGetHeightOfPt(Sender: TObject; pt: PDoublePoint): Double; procedure OnGetPathCheckOverlapMargin(Sender: TNet; Path, PathChk: TNetPath; var aMargin: Double); procedure OnMovePath(Sender: TObject); procedure OnMergeNetPathsQuery(Sender: TNet; var CanMerge: Boolean); procedure OnMergeNetsQuery(ANet1, ANet2: TNet; var CanMerge: Boolean); procedure OnMergePaths(AMainPath, APath: TNetPath); //13.01.2011 procedure OnMergePathsQuery(APath1, APath2: TNetPath; var CanMerge: Boolean); procedure OnMove(Sender: TObject); procedure OnMoveJoinedPoints(Sender: TObject); function OnMovePoint(Sender: TNet; APoint: PDoublePoint; AID: Integer): Integer; procedure OnPathsOverlapQuery(APath, ACheckPath: TNetPath; Apt: PDoublePoint; var ACanOverlap: Boolean); procedure OnResize(Sender: TObject); procedure OnScaleAfter(Sender: TObject); procedure OnScaleBefore(Sender: TObject); procedure OnScale(Sender: TObject; PercentX, PercentY: Double; rPoint: PDoublePoint); procedure OnSetScale(Sender: TObject; OldScale, NewScale: Double); procedure OnSelectObj(Sender: TObject); function OnSelectPoint(Sender: TNet; APoint: PDoublePoint; AID: Integer): Integer; procedure SetLastDoorObjSize(aDoorObjType: TDoorObjType; aVal: Double); procedure SetLastObjSize(const aKey: String; aVal: Double); //Tolik 09/11/2017 -- procedure SetLastObjParam(const aKey: String; aVal: string); // constructor Create; destructor Destroy; override; procedure AddNetToDefHeights(ANet: TObject); // Добавляет TNet на определение высот внутри других контуров // Выполняется перед началом вкидки объекта, нужно например для того, // когда добавляется УГОЛ стены нужно знать для какого он типа объекта - просто перестенок, стена комнаты, стена кир.стены procedure BeginInsertObject(AObjectType: Integer); procedure EndInsertObject(AID: Integer=0); procedure SetHandlersToObj(AObject: TObject); procedure SetRoomWallRectTool(ACAD: TForm); end; TArchObjPropExp = class(TMyObject) FCaption: String; FObjectSN: String; FPropsSN: TStringList; // сист.имена свойств, которые будут суммироваться в группе // - первым в списке будет свойство из которого создается этот объект FGroupPropsSN: TStringList; // сист.имена свойств, по которым будет идти группировка FGroupedObjects: TObjectList; // сгруппированные объекты FObjectPropsSN: TStringList; // остальные сист.имена свойств, которые пойдут в объект SC FAllObjectPropsSN: TStringList; // весь перечень свойств, которые пойдут в объект SC FPropsCorrespond: TStringList; // соответствие систюимене свойств арх.объектов и SC procedure AddPropCorrespond(const AArchPropSN, ASCPropSN: String); function AddGrpPropObj(const APropSN: string; AValue: string='0'): TStringList; procedure AddPropValToGrp(const AGrpPropSN, AGrpVal, APropSN: String; AVal: Double); function GetGrpObj(const AGrpPropSN, AGrpVal: String): TStringList; // Вернет групповой объект-StringList по названию и знач. свойства constructor Create; destructor Destroy; override; procedure DefineAllProps; end; TArchExport = class private TmpCompon: TSCSComponent; public FMaterilaRemainsGrp: TArchObjPropExp; FMaterilaRemains: TStringList; FScaleKoeff: Double; constructor Create; destructor Destroy; override; // Добавить материал в остатки function AddMaterialToRemains(AMatType: Integer; AWidth, AHeight, ARemainsMinUseSize: Double; ACount: Integer): Boolean; procedure AddPropToKey(const APropSN, AVal: String; var AKey: String); // Проверяет может ли использоваться остаток в зависимости от высоты материала function CanUseRemainByPercent(ARemainsH, AMatHeight: Double): Boolean; // Вернет процент, по которому определяем что остаток м.б. учтен если он не меньше высоты материала по этому проценту function GetHeightPersentToRemains(AHeight: Double): Double; function GetMaterilaRemainsIndex(AMatType: Integer; AWidth: Double; AKey: Pointer=nil): Integer; // Вычитать материал из остатков - вернет кол-во вычтенных function RemoveMaterialFromRemains(AMatType: Integer; AWidth, AHeight, ARemainsMinUseSize: Double; ACount: Integer): Integer; procedure Clear; end; implementation uses U_ArchCommon, U_Main, U_CAD, U_Common, PCDrawBox; { TWallDivPath } class function TWallDivPath.CreateFromShadow(aOwner: TComponent; LHandle: Integer; Shadow: TFigure): TFigure; var CAD: TForm; points: TDoublePointArr; pt: TDoublePoint; NextPt: TDoublePoint; NextPtExists: Boolean; i, j, k: Integer; TrgNet: TNet; NetRegionPathsPoints: TDoublePointArr; PathsPoints: TDoublePointArr; IsRoomOut: Boolean; Path: TNetPath; DefArchWallInfo: TArchWallInfo; ArchWallDivInfo: TArchWallDivInfo; TryCount: Integer; ip1, ip2, op1, op2: TDoublePoint; //27.08.2012 ipt: TPoint; //27.08.2012 dx,dy,z: Double; PathFullConture: TDoublePointArr; DirectionKoef: Integer; PollyRegion: Integer; PathWidthInt: Integer; begin // Result := inherited CreateFromShadow(aOwner, LHandle, Shadow); result := nil; try // *UNDO* //if GCadForm.FCanSaveForUndo then //begin // GCadForm.SaveForUndo(uat_None, True, False); // GCadForm.FCanSaveForUndo := False; //end; CAD := TForm(TPowerCad(aOwner).Owner); TF_CAD(CAD).BeginSaveForUndo(uat_None, True, False); if TWallPath(Shadow).valid and assigned(ActiveNet) then begin //10.04.2012 - значение по умолчанию DefArchWallInfo := TArchWallInfo(GetArchObjDefaultParams(ctArhWallDivision)); if DefArchWallInfo = nil then DefArchWallInfo := TArchWallInfo(GetArchObjDefaultParams(ctArhWall)); //ActiveNet.MakePath(points) ArchWallDivInfo := TArchWallDivInfo.Create(nil); ArchWallDivInfo.Thickness := 0.1; if DefArchWallInfo <> nil then begin ArchWallDivInfo.Height := DefArchWallInfo.Height; if DefArchWallInfo is TArchWallDivInfo then begin ArchWallDivInfo.Thickness := DefArchWallInfo.Thickness; ArchWallDivInfo.Coordz := TArchWallDivInfo(DefArchWallInfo).Coordz; end; end; while (Shadow.PointCount > 1) and EQDP(Shadow.FigurePoints[Shadow.PointCount], Shadow.FigurePoints[Shadow.PointCount - 1]) do begin Shadow.PointCount := Shadow.PointCount - 1; end; TrgNet := nil; IsRoomOut := false; SetLength(Points, Shadow.PointCount{-1}); SetLength(NetRegionPathsPoints, 0); For i := 1 to Shadow.PointCount{-1} do begin pt := Shadow.FigurePoints[i]; Points[i - 1] := pt; NextPtExists := false; if i < Shadow.PointCount then begin NextPt := Shadow.FigurePoints[i+1]; NextPtExists := true; end else if i > 1 then begin NextPt := Shadow.FigurePoints[1]; NextPtExists := true; end; if i = 1 then begin TrgNet := GetRoomNetByPoint(Points[i - 1], GCadForm); // Если не нашли кабинет, в котором должен рисоваться перестенок if TrgNet = nil then begin IsRoomOut := true; Break; //// BREAK //// end else // набор координат стен, образующих комнату GetNetRegionPathPoints(TrgNet, nil, NetRegionPathsPoints); end; if TrgNet <> nil then begin {//27.08.2012 dx := pt.x; dy := pt.y; z := 0; TrgNet.XDrawEngine.ConvertPoint(dx,dy,z); ipt := Point(round(dx),round(dy));} //10.04.2012 - Если точка входит в сегмент, то сместить на внутренний край сегмента TryCount := 0; //10.04.2012 - цыкл два раза, так как точка может быть в углу, тогда нужно по вертикали и горизонтали //11.04.2012 for j := 0 to TrgNet.Paths.Count - 1 do for j := 0 to TrgNet.Paths.Count - 1 do begin Path := TrgNet.Paths[j]; //Path.DefineInOutPoints; //if Path.IsPointIn(pt.x, pt.y) then // pa1-pa2 определяем как более длинная линия чем pb1-pb2 {pa1 := Path.a1; pa2 := Path.a2; pb1 := Path.b1; pb2 := Path.b2; if GetLineLength(Path.a1, Path.a2) < GetLineLength(Path.b1, Path.b2) then begin pa1 := Path.b1; pa2 := Path.b2; pb1 := Path.a1; pb2 := Path.a2; end;} {Path.DefineInOutPoints; pa1 := Path.op1^; pa2 := Path.op2^; pb1 := Path.ip1^; pb2 := Path.ip2^;} //DirectionKoef := GetParallelPointDirectionKoeff(pa1, pa2, pb1); //GetParallelPoints(pa1, pa2, pb1, pb2, DirectionKoef * Path.Width); ////GetParallelPoints(Path.p1^, Path.p2^, pa1, pa2, Path.Width/2); ////GetParallelPoints(Path.p1^, Path.p2^, pb1, pb2, -1*Path.Width/2); //PollyRegion := TPCDrawing(aOwner).Dengine.PolygonRegion(pa1, pa2, pb2, pb1); ////if PointInPolyRect(pt, Path.ip1^, Path.ip2^, Path.op2^, Path.op1^) then //PollyRegion := TPCDrawing(aOwner).Dengine.PolygonRegion(Path.GetFullConture); //if ptInRegion(PollyRegion, ipt.x, ipt.y) then // EmptyProcedure; //DeleteObject(PollyRegion); end; EmptyProcedure; for j := TrgNet.Paths.Count - 1 downto 0 do begin Path := TrgNet.Paths[j]; PollyRegion := TPCDrawing(aOwner).Dengine.PolygonRegion(Path.GetFullConture); //if Path.IsPointIn(pt.x, pt.y) then //27.08.2012 if ptInRegion(PollyRegion, ipt.x, ipt.y) then if TrgNet.XDrawEngine.IsPointInRegion(PollyRegion, @pt) then begin Path.DefineInOutPoints; ip1 := Path.ip1^; ip2 := Path.ip2^; op1 := Path.op1^; op2 := Path.op2^; if Not Path.FIsConture and NextPtExists then begin // Проверяем какая точка сегмента ближе к второй точке if GetLineLenght(Path.ip1^, NextPt) > GetLineLenght(Path.op1^, NextPt) then begin ip1 := Path.op1^; ip2 := Path.op2^; op1 := Path.ip1^; op2 := Path.ip2^; end; end; if ArchWallDivInfo.Thickness > 0 then begin // Опред. направление к внешним точкам (будем его использовать как обратное с * -1) //27.08.2012 DirectionKoef := GetParallelPointDirectionKoeff(Path.ip1^, Path.ip2^, Path.op1^); //27.08.2012 GetParallelPoints(Path.ip1^, Path.ip2^, ip1, ip2, -1 * DirectionKoef * (ArchWallDivInfo.Thickness*0.5) *(1000/ TPowerCad(TrgNet.Owner).MapScale) ); DirectionKoef := GetParallelPointDirectionKoeff(ip1, ip2, op1); GetParallelPoints(ip1, ip2, ip1, ip2, -1 * DirectionKoef * (ArchWallDivInfo.Thickness*0.5) *(1000/ TPowerCad(TrgNet.Owner).MapScale) ); end; PointToLineByAngle(ip1, ip2, pt); Points[i - 1] := pt; {//27.08.2012 - Если точка все равно пересекает сегмент, тогда подвигаем ее к второй точке if NextPtExists and TrgNet.XDrawEngine.IsPointInRegion(PollyRegion, @pt) then begin PathWidthInt := Trunc(Path.Width); for k := 1 to PathWidthInt do begin pt := MPoint(pt, NextPt, 1); if Not TrgNet.XDrawEngine.IsPointInRegion(PollyRegion, @pt) then begin Points[i - 1] := pt; Break; //// BREAK //// end; end; end;} end; DeleteObject(PollyRegion); end; EmptyProcedure; // Если точка входит в любую стену (перестенок) комнаты // ИЛИ точка выходит за пределы комнаты if {//10.04.2012 TrgNet.IsPointIn(pt.x, pt.y) or} Not IsPtInPolygon(pt, NetRegionPathsPoints) then begin IsRoomOut := true; Break; //// BREAK //// end; end; end; // Проверяем, не пересикают ли новые сегменты существующие стены/перестенки if Not IsRoomOut and (TrgNet <> nil) then begin GetPathsPoints(TrgNet.Paths, PathsPoints); if Length(PathsPoints) > 0 then for i := 1 to Length(Points) - 1 do begin for j := 1 to Length(PathsPoints) - 1 do begin if j mod 2 <> 0 then //if LinesIntersect(Points[i-1], Points[i], PathsPoints[j-1], PathsPoints[j]) then //10.04.2012 if LinesCross(Points[i-1], Points[i], PathsPoints[j-1], PathsPoints[j]) then if LinesCross(Points[i-1], Points[i], PathsPoints[j-1], PathsPoints[j], false) then begin IsRoomOut := true; Break; //// BREAK //// end; end; if IsRoomOut then Break; //// BREAK //// end; end; if Not IsRoomOut then begin TrgNet.FDisableMergePaths := true; try {//10.04.2012 DefArchWallInfo := TArchWallInfo(GetArchObjDefaultParams(ctArhWallDivision)); if DefArchWallInfo = nil then DefArchWallInfo := TArchWallInfo(GetArchObjDefaultParams(ctArhWall)); //ActiveNet.MakePath(points) ArchWallDivInfo := TArchWallDivInfo.Create(nil); ArchWallDivInfo.Thickness := 0.1; if DefArchWallInfo <> nil then begin ArchWallDivInfo.Height := DefArchWallInfo.Height; if DefArchWallInfo is TArchWallDivInfo then begin ArchWallDivInfo.Thickness := DefArchWallInfo.Thickness; ArchWallDivInfo.Coordz := TArchWallDivInfo(DefArchWallInfo).Coordz; end; end; } for i := 1 to Length(Points) - 1 do begin ArchWallDivInfo.P1 := Points[i-1]; ArchWallDivInfo.P2 := Points[i]; CreateArchWallByNet(TrgNet, ctArhWallDivision, ArchWallDivInfo); end; finally TrgNet.FDisableMergePaths := false; end; //10.04.2012 if DefArchWallInfo <> nil then //10.04.2012 DefArchWallInfo.Free; FreeAndNil(ArchWallDivInfo); RefreshNet(TrgNet); end else MessageInfo('Перегородка должна находится внутри комнаты и не пересекать стены'); if DefArchWallInfo <> nil then DefArchWallInfo.Free; end; TF_CAD(CAD).EndSaveForUndo; // *UNDO* //GCadForm.FCanSaveForUndo := True; except on E: Exception do AddExceptionToLogEx('TWallDivPath.CreateFromShadow', E.Message); end; end; { TRoomWallRect } class function TRoomWallRect.CreateFromShadow(aOwner: TComponent; LHandle: Integer; Shadow: TFigure): TFigure; var CAD: TForm; //List: TSCSList; WalsPoints: TDoublePointArr; ObjType: Integer; begin result := nil; if TWallRect(Shadow).valid and assigned(ActiveNet) then begin // *UNDO* //if GCadForm.FCanSaveForUndo then //begin // GCadForm.SaveForUndo(uat_None, True, False); // GCadForm.FCanSaveForUndo := False; //end; CAD := TForm(TPowerCad(aOwner).Owner); SetLength(WalsPoints, 5); WalsPoints[0] := Shadow.ap1; WalsPoints[1] := DoublePoint(Shadow.ap2.x, Shadow.ap1.Y); WalsPoints[2] := Shadow.ap2; WalsPoints[3] := DoublePoint(Shadow.ap1.x, Shadow.ap2.Y); WalsPoints[4] := Shadow.ap1; ObjType := TF_CAD(CAD).PCad.ToolData; if Not CheckContureIntersectNet(ObjType, @WalsPoints, CAD) then begin TF_CAD(CAD).BeginSaveForUndo(uat_None, True, False); //List := GetSCSListByCAD(CAD); try //15.10.2010 ObjType := ctArhRoom; //if Self is TBrickWallRect then //15.10.2010 if ClassName = TBrickWallRect.ClassName then //15.10.2010 ObjType := ctArhBrickWall; CreateArchRoomByWallInfo(nil, nil, CAD, ObjType, nil, WalsPoints, nil, nil, true, true); finally TF_CAD(CAD).EndSaveForUndo; end; // *UNDO* //GCadForm.FCanSaveForUndo := True; end; end; end; { TWallPolyPath } class function TWallPolyPath.CreateFromShadow(aOwner: TComponent; LHandle: Integer; Shadow: TFigure): TFigure; var CAD: TForm; points: TDoublePointArr; pt: TDoublePoint; i: Integer; ToolData: Integer; ObjType: Integer; NewArchObj: TSCSComponent; NewNet: TNet; begin result := nil; try while (Shadow.PointCount > 1) and EQDP(Shadow.FigurePoints[Shadow.PointCount], Shadow.FigurePoints[Shadow.PointCount - 1]) do begin Shadow.PointCount := Shadow.PointCount - 1; end; if Shadow.PointCount >= 4 then begin // первая и последняя точки должны совпадать if EQDP(Shadow.FigurePoints[1], Shadow.FigurePoints[Shadow.PointCount]) then begin SetLength(Points, Shadow.PointCount); For i := 1 to Shadow.PointCount do begin pt := Shadow.FigurePoints[i]; Points[i - 1] := pt; end; CAD := TForm(TPowerCad(aOwner).Owner); ObjType := TF_CAD(CAD).PCad.ToolData; //ctArhRoom; if Not IsCrossExistsByPoints(Points) then begin if Not CheckContureIntersectNet(ObjType, @Points, CAD) then begin TF_CAD(CAD).BeginSaveForUndo(uat_None, True, False); NewArchObj := CreateArchRoomByWallInfo(nil, nil, CAD, ObjType, nil, Points, nil, nil, true, true); TF_CAD(CAD).EndSaveForUndo; //if Not IsConvexPolygon(@Points) then // Messageinfo('Сегмент должен быть выпуклым'); if NewArchObj <> nil then begin NewNet := TNet(GetCADObjByArchObj(NewArchObj)); CheckNetRoofSegCortex(NewNet, NewArchObj); end; end; end else MessageInfo('Нельзя чтобы линии пересекались'); end; end; except on E: Exception do AddExceptionToLogEx('TWallPolyPath.CreateFromShadow', E.Message); end; end; { TArchEngine } procedure TArchEngine.BeginExport; begin FIsExporting := true; FExport := TArchExport.Create; end; procedure TArchEngine.EndExport; begin FIsExporting := false; FExport.Free; end; procedure TArchEngine.AfterLoadProps(AObject: TObject); var ArchObj: TSCSComponent; begin if AObject is TNetPath then begin ArchObj := GetArchObjByCADObj(TNetPath(AObject)); if ArchObj <> nil then SetNetPathColorByObj(TNetPath(AObject), ArchObj); end else if AObject is TNet then begin //DefineArchRoomCornersNamesByCadObj(AObject); end; end; function TArchEngine.GetLastDoorObjSize(aDoorObjType: TDoorObjType; aDefVal: Double): Double; begin Result := GetLastObjSize(aoskPathDoorSize + IntToStr(Ord(aDoorObjType)), aDefVal); end; function TArchEngine.GetLastObjSize(const aKey: String; aDefVal: Double): Double; var ResStr: String; begin Result := aDefVal; if FLastObjsSizes.GetVal(aKey, ResStr) then Result := StrToFloat_My(ResStr); end; //Tolik 09/11/2017 -- function TArchEngine.GetLastObjParam(const aKey: String): Boolean; var ResStr: String; begin Result := False; if FLastObjsSizes.GetVal(aKey, ResStr) then if ResStr = 'TRUE' then Result := True; end; function TArchEngine.OnAddPoint(Sender: TNet; aTrgPath: TNetPath; APoint: PDoublePoint; AID: Integer): Integer; var AArchContainer: TSCSCatalog; RoomObj: TSCSComponent; NewObj: TSCSComponent; NetPath: TNetPath; PathFromPoint: TNetPath; WallCompon: TSCSComponent; i: Integer; //SnapInfo: String; TrgPathPointObj: TSCSComponent; IsPointInBrickWall: Boolean; ObjType: Integer; ObjTypeSN: String; begin Result := AID; if Sender.FComponID <> 0 then begin AArchContainer := GetArchContainerByCADObj(Sender); RoomObj := GetArchObjByCADObj(Sender, AArchContainer); if RoomObj <> nil then begin ObjType := ctArhWallCorner; ObjTypeSN := ctsnArhWallCorner; if (RoomObj.IsLine = ctArhRoofSeg) then begin ObjType := ctArhRoofHipCorner; ObjTypeSN := ctsnArhRoofHipCorner; end; NewObj := TSCSComponent(CreateComponInPMByType(RoomObj, ObjTypeSN, ObjType)); if NewObj <> nil then begin Result := NewObj.ID; // Определяем точка на стене, или перестенке PathFromPoint := nil; WallCompon := nil; for i := 0 to Sender.Paths.Count - 1 do begin NetPath := TNetPath(Sender.Paths[i]); if (NetPath.p1 = APoint) or (NetPath.p2 = APoint) then begin PathFromPoint := NetPath; WallCompon := GetArchObjByCADObj(PathFromPoint, AArchContainer); Break; //// BREAK //// end; //if end; //SnapInfo := TPowerCad(Sender.Owner).SnapInfo; IsPointInBrickWall := (RoomObj.Isline = ctArhBrickWall) and ((FInsertingObjectType = ctArhBrickWall) or (FInsertingObjectType = ctArhWall) or (Assigned(WallCompon) and (WallCompon.IsLine = ctArhWall))); // Если не кир. стена или точка на перегородке - удаляем лишние свойства if Not IsPointInBrickWall then //if (RoomObj.Isline = ctArhRoom) or // (Assigned(WallCompon) and (WallCompon.IsLine = ctArhWallDivision)) or // (Not Assigned(WallCompon) and ((SnapInfo = 'TWallDivPath') or (SnapInfo = 'TRoomWallRect') )) then begin //NewObj.RemovePropertyBySysName(pnPlinthHeight); //NewObj.RemovePropertyBySysName(pnBasementDepth); //NewObj.RemovePropertyBySysName(pnBasementTotalHeight); NewObj.RemovePropertyBySysName(pnTrenchDepth); end; // Перетягиваем свойства из точки сегмента, на который добавляется точка TrgPathPointObj := nil; if aTrgPath <> nil then TrgPathPointObj := GetArchCornerByPoint(Sender, aTrgPath.p1); if TrgPathPointObj <> nil then NewObj.AssignProperties(TrgPathPointObj.Properties); if FInsertingObjectCount > 0 then begin FInsrtedPointsID.Add(Result); FInsrtedCorners.Add(NewObj); end; end; end; end; end; procedure TArchEngine.OnAfterDivPath(Sender: TObject); begin if (Sender is TNetPath) then if TNetPath(Sender).FComponID <> 0 then begin Self.EndInsertObject(0); end; end; procedure TArchEngine.OnAutoAddPath(Sender: TObject; SrcPath, NewPath: TNetPath); var Net: TNet; //CAD: TF_CAD; SrcObj: TSCSComponent; NBObj: TSCSComponent; NewObj: TSCSComponent; SCSList: TSCSList; ArchContainer: TSCSCatalog; CompTypeSysName: String; CompType: Integer; begin //CAD := TF_CAD(GetCADFormByObj(Sender)); if SrcPath.FComponID <> 0 then //if Sender.FComponID <> 0 then begin // Добавяляем компоненту к новому сегменту ArchContainer := GetArchContainerByCADObj(Sender); SrcObj := ArchContainer.GetComponentFromReferences(SrcPath.FComponID); if SrcObj <> nil then begin //TF_CAD(CAD).BeginSaveForUndo(uat_None, True, False); try NewObj := nil; NBObj := GetNBArchObj(SrcObj.IsLine); if NBObj <> nil then NewObj := CreateArchObj(SrcObj.Parent, NBObj) else begin CompTypeSysName := ''; CompType := ctArhWall; case SrcObj.IsLine of ctArhWall: begin CompTypeSysName := ctsnArhWall; CompType := ctArhWall; end; ctArhWallDivision: begin CompTypeSysName := ctsnArhWallDivision; CompType := ctArhWallDivision; end; ctArhRoofHip: begin CompTypeSysName := ctsnArhRoofHip; CompType := ctArhRoofHip; end; end; if CompTypeSysName <> '' then //26.04.2011 NewObj := TSCSComponent(CreateComponInPMByType(SrcObj.Parent, CompTypeSysName, ctArhWall)); NewObj := TSCSComponent(CreateComponInPMByType(SrcObj.Parent, CompTypeSysName, CompType)); end; if NewObj <> nil then begin NewObj.AssignProperties(SrcObj.Properties); NewPath.FComponID := NewObj.ID; NewPath.FOnSelect := Self.OnSelectObj; end; finally //TF_CAD(CAD).EndSaveForUndo; end; end; GArchEngine.AfterLoadProps(NewPath); end; if FGroupingMode then begin NewPath.Opath := SrcPath.Opath; NewPath.FDivedFrom := SrcPath; end; end; procedure TArchEngine.OnBeforeDivPath(Sender: TObject); var ArchObj: TSCSComponent; ObjType: Integer; begin if (Sender is TNetPath) then if TNetPath(Sender).FComponID <> 0 then begin ObjType := ctNone; ArchObj := GetArchObjByCADObj(Sender); if ArchObj <> nil then ObjType := ArchObj.IsLine; Self.BeginInsertObject(ObjType); end; end; procedure TArchEngine.OnDblClick(Sender: TObject); begin //ShowMessage(Sender.ClassName); EditCADArchObj(Sender); end; function TArchEngine.OnDefineJoinedNets(Sender: TNet; ANetList, ACheckNetList, AResJoined: TList): Boolean; var i, j: Integer; ArchObjList: TSCSComponents; Obj: TSCSComponent; CheckNetList: TList; ArchCheckObjList: TSCSComponents; Net, CheckNet: TNet; procedure FindJoined(AObj: TSCSComponent); var i: Integer; Joined, JoinedTopObj: TSCSComponent; NetFromList: TNet; begin for i := 0 to AObj.JoinedComponents.Count - 1 do begin Joined := AObj.JoinedComponents[i]; JoinedTopObj := Joined.GetTopComponent; if JoinedTopObj <> nil then if ArchCheckObjList.GetComponenByID(JoinedTopObj.ID) <> nil then begin NetFromList := GetNetByComponIDFromList(JoinedTopObj.ID, CheckNetList); if (NetFromList <> nil) then begin if (AResJoined.IndexOf(NetFromList) = -1) then AResJoined.Add(NetFromList); CheckNetList.Remove(NetFromList); ArchCheckObjList.Remove(JoinedTopObj); end; end; end; end; begin Result := false; AResJoined.Clear; if Sender.FComponID <> 0 then begin CheckNetList := TList.Create; CheckNetList.Assign(ACheckNetList); ArchObjList := GetArchObjsByCADObjs(ANetList); ArchCheckObjList := GetArchObjsByCADObjs(ACheckNetList); // Добавляем по подключениям компонентов for i := 0 to ArchObjList.Count - 1 do begin Obj := ArchObjList[i]; for j := 0 to Obj.ChildReferences.Count - 1 do FindJoined(Obj.ChildReferences[j]); end; // Добавляем по подключению к точкам for i := 0 to ANetList.Count - 1 do begin Net := TNet(ANetList[i]); for j := ACheckNetList.Count - 1 downto 0 do begin CheckNet := TNet(ACheckNetList[j]); if AResJoined.IndexOf(CheckNet) = -1 then if Net.CheckIntersect(CheckNet) then begin AResJoined.Add(CheckNet); ACheckNetList.Delete(j); end; end; if ACheckNetList.Count = 0 then Break; //// BREAK //// end; // Добавляем по подключению к точкам среди найденных if ACheckNetList.Count > 0 then begin i := 0; while i < AResJoined.Count do begin Net := TNet(AResJoined[i]); for j := ACheckNetList.Count - 1 downto 0 do begin CheckNet := TNet(ACheckNetList[j]); if AResJoined.IndexOf(CheckNet) = -1 then if Net.CheckIntersect(CheckNet) then begin AResJoined.Add(CheckNet); ACheckNetList.Delete(j); end; end; if ACheckNetList.Count = 0 then Break; //// BREAK //// inc(i); end; end; ArchObjList.Free; ArchCheckObjList.Free; CheckNetList.Free; end; end; // AllowNear: Boolean; // Позволять ли искать на тех же координатах с других TNet function TArchEngine.OnDefineMoveObjects(Sender: TNet; Apt: PDoublePoint; APath: TNetPath; ANetList: TList; AllowNear: Boolean=true): Boolean; var i, j: integer; PointObj: TSCSComponent; SegObjList: TSCSComponents; SegObjIdx: Integer; SegObj: TSCSComponent; Joined: TSCSComponent; JoinedPt: PDoublePoint; JoinedPath: TNetPath; TmpPath: TNetPath; ptSrc: PDoublePoint; JoinedTopObj: TSCSComponent; ArchObjList: TSCSComponents; Connection: PComplect; NetFromList: TNet; Net: TNet; pt: PDoublePoint; ChildObj: TSCSComponent; ptObj: TSCSComponent; //AllowNear: Boolean; // Позволять ли искать на тех же координатах с других TNet function LoadObjectsForJoined(AJoinedObj: TSCSComponent): Boolean; begin Result := false; if Joined <> nil then begin JoinedTopObj := Joined.GetTopComponent; if JoinedTopObj <> nil then if ArchObjList.GetComponenByID(JoinedTopObj.ID) <> nil then begin Connection := AJoinedObj.GetConnectionByConnected(Joined); if Connection <> nil then begin NetFromList := GetNetByComponIDFromList(JoinedTopObj.ID, ANetList); if NetFromList <> nil then Result := true end; end; end; end; procedure AddPtToJoined(AJoined: TSCSComponent); var i, j: integer; PointsNear: TList; begin JoinedPt := NetFromList.GetPointByID(AJoined.ID); if (JoinedPt = nil) and (NetFromList.FSrcNet <> nil) then begin ptSrc := NetFromList.FSrcNet.GetPointByID(AJoined.ID); if (ptSrc <> nil) and AllowNear then JoinedPt := NetFromList.GetPointByNear(ptSrc^); end; if JoinedPt <> nil then begin Result := true; if NetFromList.FJoinedMovePoints.IndexOf(JoinedPt) = -1 then begin NetFromList.FJoinedMovePoints.Add(JoinedPt); NetFromList.FJoinedMovePointsDirections.Add(Pointer(Connection^.RelType)); NetFromList.FJoinedMovePointsFixedState.Add(Pointer(Connection^.Fixed)); end; if AllowNear then for i := 0 to ANetList.Count - 1 do begin Net := TNet(ANetList[i]); {PointsNear := Net.GetPointsByNear(JoinedPt^); //23.09.2011} pt := Net.GetPointByNear(JoinedPt^); //for j := 0 to PointsNear.Count - 1 do begin //pt := PDoublePoint(PointsNear[j]); if (pt <> nil) and (pt <> JoinedPt) then if (APath = nil) or ((pt <> APath.p1) and (pt <> APath.p2)) then begin if Net.FJoinedMovePoints.IndexOf(pt) = -1 then begin PtObj := GetArchCornerByPoint(Net, pt); if (PtObj <> nil) and (PtObj.ID = 115) then EmptyProcedure; Net.FJoinedMovePoints.Add(pt); Net.FJoinedMovePointsDirections.Add(Pointer(Connection^.RelType)); Net.FJoinedMovePointsFixedState.Add(Pointer(Connection^.Fixed)); end; end; end; //PointsNear.Free; end; end; end; begin Result := false; //AllowNear := false; // Сброс //for i := 0 to ANetList.Count - 1 do //begin // Net := ANetList[i]; // Net.FJoinedMovePoints.Clear; // Net.FJoinedMovePointsDirections.Clear; // Net.FJoinedMovePointsFixedState.Clear; // Net.FJoinedMovePaths.Clear; // Net.FJoinedMovePathsDirections.Clear; //end; ClearJoinedParamsInNets(ANetList); if Sender.FComponID <> 0 then begin // Ищем объект точки, в которого есть подключенные точки PointObj := nil; if Apt <> nil then PointObj := GetArchCornerByPointWithJoined(ANetList, Apt); // Ищем объект сегмента, в которого есть подключенныя SegObjList := nil; if APath <> nil then SegObjList := GetArchSegByPtWithJoined(ANetList, APath.p1, APath.p2); if (PointObj <> nil) or (SegObjList <> nil) then begin ArchObjList := GetArchObjsByCADObjs(ANetList); if PointObj <> nil then begin for i := 0 to PointObj.JoinedComponents.Count - 1 do begin Joined := PointObj.JoinedComponents[i]; if (Joined.IsLine = PointObj.IsLine) and LoadObjectsForJoined(PointObj) then begin AddPtToJoined(Joined); end; end; end; if SegObjList <> nil then begin for SegObjIdx := 0 to SegObjList.Count - 1 do begin SegObj := SegObjList[SegObjIdx]; for i := 0 to SegObj.JoinedComponents.Count - 1 do begin Joined := SegObj.JoinedComponents[i]; if LoadObjectsForJoined(SegObj) then begin // Если подключена точка if IsArchCornerComponByIsLine(Joined.IsLine) then begin AddPtToJoined(Joined); end // Если подключено ребро/линия else if IsArchSegmentComponByIsLine(Joined.IsLine) then begin // Определяем подключенный сегмент JoinedPath := GetNetPathByComponIDFromNet(Joined.ID, NetFromList); if (JoinedPath = nil) and (NetFromList.FSrcNet <> nil) then begin for j := 0 to NetFromList.FSrcNet.Paths.Count - 1 do begin TmpPath := TNetPath(NetFromList.FSrcNet.Paths[j]); if Assigned(TmpPath.Opath) and (TmpPath.Opath.FComponID = Joined.ID) then begin JoinedPath := TmpPath.Opath; Break; //// BREAK //// end; end; end; if JoinedPath <> nil then begin Result := true; NetFromList.FJoinedMovePaths.Add(JoinedPath); NetFromList.FJoinedMovePathsDirections.Add(Pointer(Connection^.RelType)); if AllowNear then for j := 0 to ANetList.Count - 1 do begin Net := TNet(ANetList[j]); TmpPath := Net.GetPathByNearPoints(JoinedPath.p1, JoinedPath.p2); if (TmpPath <> nil) and (TmpPath <> JoinedPath) then begin if TmpPath <> APath then begin Net.FJoinedMovePaths.Add(TmpPath); Net.FJoinedMovePathsDirections.Add(Pointer(Connection^.RelType)); end; end else begin pt := Net.GetPointByNear(JoinedPath.p1^); if (pt <> nil) and (pt <> JoinedPath.p1) then if Net.FJoinedMovePoints.IndexOf(pt) = -1 then begin PtObj := GetArchCornerByPoint(Net, pt); if (PtObj <> nil) and (PtObj.ID = 115) then EmptyProcedure; Net.FJoinedMovePoints.Add(pt); Net.FJoinedMovePointsDirections.Add(Pointer(Connection^.RelType)); Net.FJoinedMovePointsFixedState.Add(Pointer(Connection^.Fixed)); end; pt := Net.GetPointByNear(JoinedPath.p2^); if (pt <> nil) and (pt <> JoinedPath.p2) then if Net.FJoinedMovePoints.IndexOf(pt) = -1 then begin PtObj := GetArchCornerByPoint(Net, pt); if (PtObj <> nil) and (PtObj.ID = 115) then EmptyProcedure; Net.FJoinedMovePoints.Add(pt); Net.FJoinedMovePointsDirections.Add(Pointer(Connection^.RelType)); Net.FJoinedMovePointsFixedState.Add(Pointer(Connection^.Fixed)); end; end; end; end; end // Если подключен сегмент else if IsArchTopComponByIsLine(Joined.IsLine) then begin if LoadObjectsForJoined(SegObj) then begin // Запоминаем все точки сегмента для перемещения for j := 0 to Joined.ChildReferences.Count - 1 do begin ChildObj := Joined.ChildReferences[j]; if IsArchCornerComponByIsLine(ChildObj.IsLine) then AddPtToJoined(ChildObj); end; end; end; end; end; end; SegObjList.Free; end; ArchObjList.Free; end; end; end; procedure TArchEngine.OnDoorChangePathQuery(Sender: TNetDoor; APath, ANewPath: TNetPath; var CanChange: Boolean); begin if Sender.FComponID <> 0 then CanChange := APath = ANewPath; end; procedure TArchEngine.OnDeleteObj(Sender: TObject); begin FDeletingObject := Sender; DelArchObjByCADObj(Sender); // Если удаляется сегмент, то переопределяем наименования углов комнаты if Sender is TNetPath then DefineArchWallCornersNamesByCadObj(Sender); //DefineArchRoomCornersNamesByCadObj(Sender); if Sender is TNet then if FNetsToDefHeights <> nil then FNetsToDefHeights.Remove(Sender); end; function TArchEngine.OnDeletePoint(Sender: TNet; APoint: PDoublePoint; AID: Integer): Integer; var RoomObj: TSCSComponent; DelObj: TSCSComponent; begin Result := AID; if Sender.FComponID <> 0 then begin RoomObj := GetArchObjByCADObj(Sender); if RoomObj <> nil then begin DelObj := RoomObj.GetComponentFromReferences(AID); if DelObj <> nil then DeleteComponInPM(DelObj.ListID, DelObj.ID, DelObj); ///Result := DelObj.ID; end; end; end; procedure TArchEngine.OnDuplicate(SrcObj, NewObj: TObject); var SrcCompon: TSCSComponent; NewCompon: TSCSComponent; IDNewComponent: Integer; ArchObj: TSCSComponent; ArchContainer: TSCSCatalog; i, j: Integer; NewPath: TNetPath; NewDoor: TNetDoor; NewPt, SrcPt, TempPt: PDoublePoint; SrcPtID: Integer; NewPathObjs: TList; LookedSrcPoints: TList; begin if (SrcObj is TNet) and (NewObj is TNet) then begin if (TNet(SrcObj).FComponID <> 0) then begin ArchContainer := GetArchContainerByCADObj(SrcObj); if ArchContainer <> nil then begin F_ProjMan.FindComponOrDirInTree(ArchContainer.ID, false); SrcCompon := GetArchObjByCadObj(SrcObj, ArchContainer); IDNewComponent := F_ProjMan.CopyComponentFromNbToPm(TForm(F_ProjMan), TForm(F_ProjMan), nil, ArchContainer.TreeViewNode, SrcCompon.ID, ckCompon); //IDNewComponent := CopyComponentFromNbToPm(TForm(F_ProjMan), TForm(F_ProjMan), nil, TrgNode, SrcComponent.ID, ckCompon); //NewCompon := if IDNewComponent <> 0 then begin NewCompon := ArchContainer.GetComponentFromReferences(IDNewComponent); TNet(NewObj).FComponID := NewCompon.ID; NewPathObjs := TList.Create; // Определяем ID для сегментов, окон, дверей for i := 0 to TNet(NewObj).Paths.Count - 1 do begin NewPath := TNetPath(TNet(NewObj).Paths[i]); ArchObj := GetComponentByOldIDFromCompon(NewCompon, NewPath.Opath.FComponID); if ArchObj <> nil then begin NewPath.FComponID := ArchObj.ID; NewPathObjs.Add(NewPath); end; for j := 0 to NewPath.Doors.Count - 1 do begin NewDoor := TNetDoor(NewPath.Doors[j]); ArchObj := GetComponentByOldIDFromCompon(NewCompon, NewDoor.FSrcDoor.FComponID); if ArchObj <> nil then NewDoor.FComponID := ArchObj.ID; end; NewPath.Opath := nil; end; // Определяем ID точек-углов if TNet(NewObj).Points.Count > 0 then begin LookedSrcPoints := TList.Create; for i := 0 to TNet(NewObj).Points.Count - 1 do begin NewPt := TNet(NewObj).Points[i]; SrcPt := TNet(SrcObj).GetPointByNear(NewPt^, LookedSrcPoints); if SrcPt <> nil then begin LookedSrcPoints.Add(SrcPt); SrcPtID := TNet(SrcObj).GetPointID(SrcPt); if SrcPtID <> 0 then begin ArchObj := GetComponentByOldIDFromCompon(NewCompon, SrcPtID); if ArchObj <> nil then begin TNet(NewObj).SetPointID(NewPt, ArchObj.ID); DefineArchCornerName(ArchObj, TNet(NewObj)); end; end; end; end; LookedSrcPoints.Free; end; //for i := 0 to NewPathObjs.Count - 1 do //begin // DefineArchWallCornersNamesByCadObj(TObject(NewPathObjs[i])); //end; NewPathObjs.Free; end; TNet(NewObj).FSrcNet := nil; end; end; end; end; function TArchEngine.OnGetHeight(Sender: TObject): Double; var ArchObj: TSCSComponent; begin Result := 0; if (Sender is TNetPath) and (TNetPath(Sender).FComponID <> 0) then begin ArchObj := GetArchObjByCADObj(Sender); if ArchObj <> nil then Result := ArchObj.GetPropertyValueAsFloat(pnHeight); end; end; function TArchEngine.OnGetHeightOfPt(Sender: TObject; pt: PDoublePoint): Double; var Path: TNetPath; RelPathList: TList; RelPath: TNetPath; TopObj: TSCSComponent; ArchObj: TSCSComponent; i: integer; Corner: TSCSComponent; h: Double; ListOwner: TSCSList; begin Result := 0; if (Sender is TNetPath) and (TNetPath(Sender).FComponID <> 0) then begin ListOwner := nil; Path := TNetPath(Sender); Corner := GetArchCornerByPoint(Path.Net, pt, Path.Opath <> nil); if Corner <> nil then Result := Corner.GetPropertyValueAsFloat(pnHeight); // Если на точке не задана высота, то берем максимальную с привязаных сегментов if Result = 0 then begin RelPathList := Path.Net.GetPathListByPoint(pt); if RelPathList.Count > 0 then begin TopObj := GetArchObjByCADObj(Path.Net); for i := 0 to RelPathList.Count - 1 do begin RelPath := TNetPath(RelPathList[i]); ArchObj := TopObj.GetComponentFromReferences(RelPath.FComponID); if (ArchObj = nil) and (RelPath.Opath <> nil) then begin if ListOwner = nil then ListOwner := TopObj.GetListOwner; if ListOwner <> nil then ArchObj := ListOwner.GetComponentFromReferences(RelPath.FComponID); end; if ArchObj <> nil then begin h := ArchObj.GetPropertyValueAsFloat(pnHeight); if h > Result then Result := h; end; end; end; RelPathList.Free; end; end; end; procedure TArchEngine.OnGetPathCheckOverlapMargin(Sender: TNet; Path, PathChk: TNetPath; var aMargin: Double); var NetObj: TSCSComponent; Obj, ObjChk: TSCSComponent; begin //Если сравнивается преегородка с чемто, то отступ будет 0, дабы перемещалися в притык if Sender.FComponID <> 0 then begin NetObj := GetArchObjByCADObj(Sender); if NetObj <> nil then begin Obj := NetObj.GetComponentFromReferences(Path.FComponID); if Obj <> nil then if Obj.IsLine = ctArhWallDivision then aMargin := 0; if aMargin <> 0 then begin ObjChk := NetObj.GetComponentFromReferences(Path.FComponID); if ObjChk <> nil then if ObjChk.IsLine = ctArhWallDivision then aMargin := 0; end; end; end; end; procedure TArchEngine.OnMovePath(Sender: TObject); begin end; procedure TArchEngine.OnMergeNetPathsQuery(Sender: TNet; var CanMerge: Boolean); begin CanMerge := Sender.FComponID = 0; end; procedure TArchEngine.OnMergeNetsQuery(ANet1, ANet2: TNet; var CanMerge: Boolean); var Obj1, Obj2: TSCSComponent; begin CanMerge := (ANet1.FComponID <> 0) and (ANet2.FComponID <> 0); if CanMerge then begin Obj1 := GetArchObjByCADObj(ANet1); Obj2 := GetArchObjByCADObj(ANet2); if Assigned(Obj1) and Assigned(Obj2) then CanMerge := Obj1.IsLine = Obj2.IsLine; end; end; procedure TArchEngine.OnMergePaths(AMainPath, APath: TNetPath); var ArchObjMain, ArchObj: TSCSComponent; begin if (AMainPath.FComponID <> 0) and (APath.FComponID <> 0) then if Not AMainPath.IsArc and Not APath.IsArc then begin //if AMainPath.Len > APath.Len then begin //ArchObjMain, ArchObj ArchObjMain := GetArchObjByCADObj(AMainPath); ArchObj := GetArchObjByCADObj(APath); APath.Width := AMainPath.Width; SetNetPathChildsWidth(ArchObj, APath, AMainPath.Width); end; end; end; procedure TArchEngine.OnMergePathsQuery(APath1, APath2: TNetPath; var CanMerge: Boolean); var Obj1, Obj2: TSCSComponent; begin Obj1 := GetArchObjByCADObj(APath1); Obj2 := GetArchObjByCADObj(APath2); CanMerge := (Obj1 <> nil) and (Obj2 <> nil) and (((Obj1.IsLine = ctArhWall) and (Obj2.IsLine = ctArhWall)) or ((Obj1.IsLine = ctArhRoofHip) and (Obj2.IsLine = ctArhRoofHip))); end; procedure TArchEngine.OnMove(Sender: TObject); begin AddNetToDefHeights(Sender); end; procedure TArchEngine.OnMoveJoinedPoints(Sender: TObject); begin AddNetToDefHeights(Sender); end; function TArchEngine.OnMovePoint(Sender: TNet; APoint: PDoublePoint; AID: Integer): Integer; var ArchCorner: TSCSComponent; Prop: PProperty; begin // Sender.FRelatedMPoint - чтобы для связанных точек не вызывать одно и тоже if (Sender.FComponID <> 0) and (Sender.FRelatedMPoint = nil) {and (Sender.FRelatedNets.Count = 0)} then begin ArchCorner := GetArchCornerByPoint(Sender, APoint); if ArchCorner <> nil then begin if ArchCorner.GetPropertyValueAsFloat(pnHeight) <> 0 then begin Prop := ArchCorner.GetPropertyBySysName(pnHeight); if Prop <> nil then OnSetArchObjProp(Prop, Prop, ArchCorner); end; end; // Является ли сегмент крыши выпуклым CheckNetRoofSegCortex(Sender, nil); AddNetToDefHeights(TNet(Sender)); end; end; procedure TArchEngine.OnPathsOverlapQuery(APath, ACheckPath: TNetPath; Apt: PDoublePoint; var ACanOverlap: Boolean); var ArchObj: TSCSComponent; ArchCheckObj: TSCSComponent; Objh1, Objh2: Double; ChkObjh1, ChkObjh2, ptH: Double; begin ACanOverlap := false; if APath.Net = ACheckPath.Net then begin ArchObj := GetArchObjByCADObj(APath); ArchCheckObj := GetArchObjByCADObj(ACheckPath); if (ArchObj <> nil) and (ACheckPath <> nil) then if (ArchObj.IsLine = ctArhRoofHip) and (ArchCheckObj.IsLine = ctArhRoofHip) then //15.08.2011 if GetArchWallCornersHeights(ArchObj, Objh1, Objh2) and //15.08.2011 GetArchWallCornersHeights(ArchCheckObj, ChkObjh1, ChkObjh2) then begin {Objh1 := APath.GetHeightOfPt(APath.p1); Objh2 := APath.GetHeightOfPt(APath.p2); ChkObjh1 := ACheckPath.GetHeightOfPt(ACheckPath.p1); ChkObjh2 := ACheckPath.GetHeightOfPt(ACheckPath.p2); //15.08.2011 //ptH := -1; //if Apt = APath.p1 then // ptH := Objh1 //else //if Apt = APath.p2 then // ptH := Objh2; //if (ptH <> -1) and ((ptH <> ChkObjh1) or (ptH <> ChkObjh2)) then // ACanOverlap := true; if (Objh1 <> ChkObjh1) or (Objh1 <> ChkObjh2) or (Objh2 <> ChkObjh1) or (Objh2 <> ChkObjh2) then} ACanOverlap := true; end; end; end; procedure TArchEngine.OnResize(Sender: TObject); var Obj: TObject; ArchObj: TSCSComponent; begin Obj := nil; if Sender is TNetDoor then begin Obj := TNetDoor(Sender).GetPath; // Подгружаем параметры окна/двери //ArchObj := GetArchObjByCADObj(Sender); //if ArchObj <> nil then // LoadArchObjPropsFromCAD(ArchObj, Sender); end else begin // Если менял ширину сегмент, обновим длины дверей/окон... if Sender is TNetPath then TNetPath(Sender).Net.CalculatePathPoints else if Sender is TNet then TNet(Sender).CalculatePathPoints; Obj := GetNetFromCADObj(Sender); end; if Obj <> nil then begin ArchObj := GetArchObjByCADObj(Obj); if ArchObj <> nil then begin DefineArchObjPropsOnResize(ArchObj, Obj); end; // Является ли сегмент крыши выпуклым if Obj is TNet then begin CheckNetRoofSegCortex(TNet(Obj), ArchObj); AddNetToDefHeights(TNet(Obj)); end else if Obj is TNetPath then AddNetToDefHeights(TNetPath(Obj).Net); end; end; procedure TArchEngine.OnScaleAfter(Sender: TObject); begin FLookedPointsOnScale.Clear; FLookedPointNetsOnScale.Clear; ClearList(FSavedLookedPointsOnScale); FScaleObjectCount := FScaleObjectCount - 1; if FScaleObjectCount < 0 then FScaleObjectCount := 0; end; procedure TArchEngine.OnScaleBefore(Sender: TObject); begin FLookedPointsOnScale.Clear; FLookedPointNetsOnScale.Clear; ClearList(FSavedLookedPointsOnScale); FScaleObjectCount := FScaleObjectCount + 1; end; procedure TArchEngine.OnScale(Sender: TObject; PercentX, PercentY: Double; rPoint: PDoublePoint); var NetList: TList; RelatedNets: TList; i, j, k: Integer; Path: TNetPath; Net: TNet; NetMoved: Boolean; p1Saved, p2Saved, p1SavedScaled, p2SavedScaled: PDoublePoint; JoinedPt: PDoublePoint; JoinedPtId: Integer; JoinedSavedPt: PDoublePoint; RelType: Integer; FixedState: Integer; PtObj: TSCSComponent; LookedIdx: Integer; ptrSavedScalePt: PDoublePoint; pt: PDoublePoint; Log: TStringList; procedure AddToLog(Indent: Integer; const AStr: String); begin Log.Add(DupStr(' ', Indent*2) + AStr); end; begin if (Sender is TNet) and (TNet(Sender).FComponID <> 0) and TNet(Sender).CanMoveJoined then begin // Определяем все связанные TNet RelatedNets := TNet(Sender).GetRelatedNetsByPoints(nil, nil, citNone, true); NetList := TList.Create; if RelatedNets <> nil then NetList.Assign(RelatedNets); NetList.Insert(0, TNet(Sender)); Log := TStringList.Create; AddToLog(0, ''); AddToLog(0, 'TNet(Sender).FComponID = ' + IntToStr(TNet(Sender).FComponID)); AddToLog(0, 'NetList.Count = ' + IntToStr(NetList.Count)); // OnDefineMoveObjects(Sender: TNet; Apt: PDoublePoint; APath: TNetPath; ANetList: TList): Boolean; // Перебираем все сегменты и смотрим еслть ли подключенные точки на них for i := 0 to TNet(Sender).Paths.Count - 1 do begin Path := TNetPath(TNet(Sender).Paths[i]); AddToLog(1, 'Path.FComponID = ' + IntToStr(Path.FComponID)); // Обределяем связанные точки для сегмента Path, // флаг AllowNear = false чтобы не добавляли точку по координатам, // так как в список она может попасть по координатам раньше времени как не Fixed, а на другом подключении окажется что Fixed, но будет уже в пролете if OnDefineMoveObjects(TNet(Sender), nil, Path, NetList, false) then begin p1Saved := TNet(Sender).GetSavedPtByPoint(Path.p1); p2Saved := TNet(Sender).GetSavedPtByPoint(Path.p2); if (p1Saved <> nil) and (p2Saved <> nil) then for j := 0 to NetList.Count - 1 do begin Net := TNet(NetList[j]); AddToLog(2, 'Net.FJoinedMovePoints.Count = ' + IntToStr(Net.FJoinedMovePoints.Count)); if (Net.FJoinedMovePoints.Count > 0) and (Net.FJoinedMovePoints.Count = Net.FJoinedMovePointsDirections.Count) then begin NetMoved := false; for k := 0 to Net.FJoinedMovePoints.Count - 1 do begin JoinedPt := PDoublePoint(Net.FJoinedMovePoints[k]); JoinedPtId := Net.GetPointID(JoinedPt); AddToLog(3, 'JoinedPtId = ' + IntToStr(JoinedPtId)); PtObj := GetArchCornerByPoint(Net, JoinedPt); if PtObj <> nil then EmptyProcedure; LookedIdx := FLookedPointsOnScale.IndexOf(JoinedPt); if (FScaleObjectCount <= 1) or (LookedIdx = -1) then begin {//23.09.2011 FLookedPointsOnScale.Add(JoinedPt); GetMem(ptrSavedScalePt, SizeOf(TDoublePoint)); ptrSavedScalePt^ := JoinedPt^; FSavedLookedPointsOnScale.Add(ptrSavedScalePt);} RelType := Integer(Net.FJoinedMovePointsDirections[k]); FixedState := Integer(Net.FJoinedMovePointsFixedState[k]); if (FixedState = biTrue) and (RelType = crtDirect) then begin JoinedSavedPt := Net.GetSavedPtByPoint(JoinedPt); if JoinedSavedPt <> nil then begin //JoinedPt^.x := JoinedSavedPt^.x + (Path.p1^.x - p1Saved^.x); //JoinedPt^.y := JoinedSavedPt^.y + (Path.p1^.y - p1Saved^.y); //23.09.2011 JoinedPt^.x := JoinedSavedPt^.x + (Path.p1^.x-p1Saved^.x + Path.p2^.x-p2Saved^.x)/2; //23.09.2011 JoinedPt^.y := JoinedSavedPt^.y + (Path.p1^.y-p1Saved^.y + Path.p2^.y-p2Saved^.y)/2; p1SavedScaled := TNet(Sender).GetSavedScaledPtByPoint(Path.p1); p2SavedScaled := TNet(Sender).GetSavedScaledPtByPoint(Path.p2); if (p1SavedScaled <> nil) and (p2SavedScaled <> nil) then begin JoinedPt^.x := JoinedSavedPt^.x + (p1SavedScaled^.x-p1Saved^.x + p2SavedScaled^.x-p2Saved^.x)/2; JoinedPt^.y := JoinedSavedPt^.y + (p1SavedScaled^.y-p1Saved^.y + p2SavedScaled^.y-p2Saved^.y)/2; NetMoved := true; end; FLookedPointsOnScale.Add(JoinedPt); FLookedPointNetsOnScale.Add(Net); GetMem(ptrSavedScalePt, SizeOf(TDoublePoint)); ptrSavedScalePt^ := JoinedPt^; FSavedLookedPointsOnScale.Add(ptrSavedScalePt); end; end; if NetMoved then AddNetToDefHeights(TNet(Net)); end // Если эта точка была перемещена, то возвращаем ее обратно else if LookedIdx <> -1 then begin //JoinedPt^ := PDoublePoint(FSavedLookedPointsOnScale[LookedIdx])^; end; end; end; end; end; end; // Перемещаем точки которые были связанны до scale for i := 0 to FLookedPointsOnScale.Count - 1 do begin pt := PDoublePoint(FLookedPointsOnScale[i]); p1Saved := TNet(FLookedPointNetsOnScale[i]).GetSavedPtByPoint(pt); if p1Saved <> nil then for j := 0 to NetList.Count - 1 do begin Net := TNet(NetList[j]); for k := 0 to Net.Points.Count - 1 do begin JoinedPt := Net.Points[k]; if FLookedPointsOnScale.IndexOf(JoinedPt) = -1 then begin p2Saved := Net.GetSavedPtByPoint(JoinedPt); if (p2Saved <> nil) and (PointNear(p1Saved^, p2Saved^)) then JoinedPt^ := pt^; end; end; end; end; NetList.Free; RelatedNets.Free; //Log.SaveToFile('C:\Temp\SCS\OnScale_'+IntToStr(TNet(Sender).FComponID)+'_norm.txt'); Log.Free; AddNetToDefHeights(TNet(Sender)); end; end; procedure TArchEngine.OnSetScale(Sender: TObject; OldScale, NewScale: Double); var ArchObj, ArchChildObj: TSCSComponent; i: Integer; ScaleKoeff: Double; begin ArchObj := GetArchObjByCADObj(Sender); if ArchObj <> nil then begin ScaleKoeff := NewScale / OldScale; // Изменяем ширины откосов { for i := 0 to ArchObj.ChildReferences.Count - 1 do begin ArchChildObj := ArchObj.ChildReferences[i]; if IsSlopeComponByIsLine(ArchChildObj.IsLine) or IsArchBalconyChildComponByIsLine(ArchChildObj.IsLine) then ArchChildObj.MulPropertyValueAsFloat(pnWidth, ScaleKoeff); end; } end; end; procedure TArchEngine.OnSelectObj(Sender: TObject); var Net: TNet; ArchObj: TSCSComponent; OrderType: Integer; begin //SelectArchObjByCADObj(Sender); // Net на верхний план Net := GetNetFromCADObj(Sender); if (Net <> nil) and (Net.Owner <> nil) then begin ArchObj := GetArchObjByCADObj(Net); OrderType := 1; if (Sender is TNetPath) and (ArchObj <> nil) then begin // TNetPath(Sender).TestShowPointsInfo; // Если выделено два ребра крыши, то отображаем угол спроецированный на 2D //if (ArchObj.IsLine = ctArhRoofSeg) then // ShowNetSelPathsAngleInCAD(Net, ArchObj); // Если кликаем по сегменту с Alt, то даем возможность на след-м клике выбрать сегмент другого TNet //if ssAlt in GGlobalShiftState then // OrderType := -1; end; if OrderType = 1 then {FigureBringToFront(Net) //}TPowerCad(Net.Owner).OrderFigureToFront(Net) else if OrderType = -1 then {FigureSendToBack(Net); //}TPowerCad(Net.Owner).OrderFigureToBack(Net); end; SelectArchObjByCADObj(Sender); FPrevSelCADObj := Sender; end; function TArchEngine.OnSelectPoint(Sender: TNet; APoint: PDoublePoint; AID: Integer): Integer; var ArchObj: TSCSComponent; PointObj: TSCSComponent; begin if Sender.FComponID <> 0 then begin ArchObj := GetArchObjByCADObj(Sender); if ArchObj <> nil then TF_Main(ArchObj.ActiveForm).SelectComponByIDInTree(AID); end; end; procedure TArchEngine.SetLastDoorObjSize(aDoorObjType: TDoorObjType; aVal: Double); begin SetLastObjSize(aoskPathDoorSize + IntToStr(Ord(aDoorObjType)), aVal); end; procedure TArchEngine.SetLastObjSize(const aKey: String; aVal: Double); begin FLastObjsSizes.SetVal(aKey, FloatToStr(aVal)); end; // Tolik 09/11/25017 -- procedure TArchEngine.SetLastObjParam(const aKey: String; aVal: string); begin FLastObjsSizes.SetVal(aKey, aVal); end; procedure TArchEngine.SetHandlersToObj(AObject: TObject); var NetDoor: TNetDoor; NetPath: TNetPath; Net: TNet; begin if AObject is TNetDoor then begin NetDoor := TNetDoor(AObject); //if NetDoor.FComponID <> 0 then begin NetDoor.FOnDoorChangePathQuery := Self.OnDoorChangePathQuery; NetDoor.FOnDblClick := Self.OnDblClick; NetDoor.FOnDelete := Self.OnDeleteObj; NetDoor.FOnResize := Self.OnResize; //17.12.2010 NetDoor.FOnSelect := Self.OnSelectObj; end; end else if AObject is TNetPath then begin NetPath := TNetPath(AObject); //if NetPath.FComponID <> 0 then begin NetPath.FOnAfterDiv := Self.OnAfterDivPath; NetPath.FOnBeforeDiv := Self.OnBeforeDivPath; NetPath.FOnDblClick := Self.OnDblClick; NetPath.FOnDelete := Self.OnDeleteObj; NetPath.FOnGetHeight := Self.OnGetHeight; NetPath.FOnGetHeightOfPt := Self.OnGetHeightOfPt; NetPath.FOnGetPathCheckOverlapMargin := Self.OnGetPathCheckOverlapMargin; NetPath.FOnSelect := Self.OnSelectObj; end; if NetPath.Net.Owner <> nil then begin //NetPath.FOnGetShowPathLength := TF_CAD(NetPath.Net.Owner.Owner).OnGetShowPathLength; //NetPath.FOnGetShowPathTraceLength := TF_CAD(NetPath.Net.Owner.Owner).OnGetShowPathTraceLength; NetPath.FOnGetShowPathLengthType := TF_CAD(NetPath.Net.Owner.Owner).OnGetShowPathLengthType; NetPath.FOnGetShowPathTraceLengthType := TF_CAD(NetPath.Net.Owner.Owner).OnGetShowPathTraceLengthType; end; end else if AObject is TNet then begin Net := TNet(AObject); //if Net.FComponID <> 0 then begin Net.FOnAddPoint := Self.OnAddPoint; //04.10.2010 Net.FOnAutoAddPath := Self.OnAutoAddPath; Net.FOnDefineJoinedNets := Self.OnDefineJoinedNets; Net.FOnDefineMoveObjects := Self.OnDefineMoveObjects; Net.FOnDelete := Self.OnDeleteObj; Net.FOnDeletePoint := Self.OnDeletePoint; //04.10.2010 Net.FOnDuplicate := Self.OnDuplicate; //16.05.2011 Net.FOnMergeNetPathsQuery := Self.OnMergeNetPathsQuery; Net.FOnMergeNetsQuery := Self.OnMergeNetsQuery; //21.10.2010 Net.FOnMergePaths := Self.OnMergePaths; //13.01.2011 Net.FOnMergePathsQuery := Self.OnMergePathsQuery; //21.10.2010 Net.FOnMove := Self.OnMove; //09.06.2011 Net.FOnMoveJoinedPoints := Self.OnMoveJoinedPoints; //09.06.2011 Net.FOnResize := Self.OnResize; //17.12.2010 Net.FOnScale := Self.OnScale; Net.FOnScaleAfter := Self.OnScaleAfter; Net.FOnScaleBefore := Self.OnScaleBefore; Net.FOnSetScale := Self.OnSetScale; Net.FOnSelectPoint := Self.OnSelectPoint; Net.FOnMovePoint := Self.OnMovePoint; Net.FOnPathsOverlapQuery := Self.OnPathsOverlapQuery; end; end; end; procedure TArchEngine.SetRoomWallRectTool(ACAD: TForm); begin FCADToSetTool := ACAD; FClassSetTool := TRoomWallRect; if FTimerSetTool = nil then FTimerSetTool := CreateTimer(200, FOnTimer); //08.06.2011 begin // FTimerSetTool := TTimer.Create(nil); // FTimerSetTool.Enabled := false; // FTimerSetTool.Interval := 200; // FTimerSetTool.OnTimer := FOnTimer; //end; FTimerSetTool.Enabled := true; FToolData := 0; end; constructor TArchEngine.Create; begin FTimerSetTool := nil; FCADToSetTool := nil; FClassSetTool := nil; FTimerDefNetHeights := nil; FNetsToDefHeights := nil; FInsertingObjectType := ctNone; FInsertingObjectCount := 0; FInsrtedPointsID := TIntList.Create; FInsrtedCorners := TSCSComponents.Create(false); FLookedPointsOnScale := TList.Create; FLookedPointNetsOnScale := TList.Create; //23.09.2011 FSavedLookedPointsOnScale := TList.Create; FScaleObjectCount := 0; FGroupingMode := false; FIsExporting := false; FExport := nil; FPrevSelCADObj := nil; FLastObjsSizes := TStringsHash.Create; end; destructor TArchEngine.Destroy; begin if FTimerSetTool <> nil then FTimerSetTool.Free; if FTimerDefNetHeights <> nil then FTimerDefNetHeights.Free; if FNetsToDefHeights <> nil then FNetsToDefHeights.Free; FInsrtedPointsID.Free; FInsrtedCorners.Free; FLookedPointsOnScale.Free; FLookedPointNetsOnScale.Free; // Tolik 03/05/2019 -- //FSavedLookedPointsOnScale.Free; FreeList(FSavedLookedPointsOnScale); // if FLastObjsSizes <> nil then FreeAndNil(FLastObjsSizes); inherited; end; procedure TArchEngine.BeginInsertObject(AObjectType: Integer); begin if FInsertingObjectCount = 0 then begin FInsertingObjectType := AObjectType; end; FInsertingObjectCount := FInsertingObjectCount + 1; end; procedure TArchEngine.EndInsertObject(AID: Integer=0); begin if FInsertingObjectCount > 0 then begin FInsertingObjectCount := FInsertingObjectCount - 1; if FInsertingObjectCount = 0 then begin // Определяет наименования для добавленых УГЛОВ СТЕНЫ DefineArchCornersNames(FInsrtedCorners); FInsertingObjectType := ctNone; FInsrtedPointsID.Clear; FInsrtedCorners.Clear; end; end; end; procedure TArchEngine.AddNetToDefHeights(ANet: TObject); begin if (ANet is TNet) and (TNet(ANet).FComponID <> 0) and (TNet(ANet).DrawStyle <> dsTrace) then begin if FNetsToDefHeights = nil then FNetsToDefHeights := TList.Create; if FTimerDefNetHeights = nil then FTimerDefNetHeights := CreateTimer(500, FOnTimerDefNetHeights); if FNetsToDefHeights.IndexOf(ANet) = -1 then begin FNetsToDefHeights.Add(ANet); RestartTimer(FTimerDefNetHeights); //FTimerDefNetHeights.Enabled := true; end; end; end; function TArchEngine.CreateTimer(AInterval: Integer; AOnTimer: TNotifyEvent): TTimer; begin Result := TTimer.Create(nil); Result.Enabled := false; Result.Interval := AInterval; Result.OnTimer := AOnTimer; end; procedure TArchEngine.FOnTimer(Sender: TObject); var CurrPos: TPoint; CAD: TF_CAD; begin if Sender = FTimerSetTool then begin TTimer(Sender).Enabled := False; if (FCADToSetTool <> nil) and (FClassSetTool <> nil) then begin CAD := TF_CAD(FCADToSetTool); GetCursorPos(CurrPos); CurrPos := CAD.PCad.ScreenToClient(CurrPos); RaiseActiveNet(CAD); if CAD.CurrentLayer <> lnArch then CAD.CurrentLayer := lnArch; CAD.PCad.SetTool(toFigure, FClassSetTool.ClassName, FToolData); CAD.PCad.SimulateUp(CAD.CurrX, CAD.CurrY); end; end; end; procedure TArchEngine.FOnTimerDefNetHeights(Sender: TObject); var i: Integer; begin TTimer(Sender).Enabled := false; try for i := 0 to FNetsToDefHeights.Count - 1 do DefineArchNetPointsHeight(TNet(FNetsToDefHeights[i])); finally FNetsToDefHeights.Clear; end; end; { TArchObjPropExp } procedure TArchObjPropExp.AddPropCorrespond(const AArchPropSN, ASCPropSN: String); begin AddStrObjToStrings(FPropsCorrespond, AArchPropSN, ASCPropSN); end; function TArchObjPropExp.AddGrpPropObj(const APropSN: string; AValue: string): TStringList; begin //Result := Self.GetGrpObj(APropSN); //if Result = nil then //begin Result := TStringList.Create; AddGUIDIDToStrings(APropSN, AValue, 0, Result); Self.FGroupedObjects.Add(Result); Self.FPropsSN.Add(APropSN); //end; end; procedure TArchObjPropExp.AddPropValToGrp(const AGrpPropSN, AGrpVal, APropSN: String; AVal: Double); var GrpObject: TStringList; PropVal: String; begin // Ищем групповой объект по имени свойства и значению GrpObject := GetGrpObj(AGrpPropSN, AGrpVal); // Если не нашли то создаем и добавляем групповое свойство if GrpObject = nil then begin GrpObject := AddGrpPropObj(APropSN); FGroupPropsSN.Add(AGrpPropSN); AddGUIDIDToStrings(AGrpPropSN, AGrpVal, 0, GrpObject); end; if GrpObject <> nil then begin PropVal := GetGUIDFromStrings(GrpObject, APropSN); if PropVal <> '' then PropVal := FloatToStrU(StrToFloatU(PropVal) + AVal) else PropVal := FloatToStrU(AVal); SetGUIDToStrings(GrpObject, PropVal, APropSN); end; end; function TArchObjPropExp.GetGrpObj(const AGrpPropSN, AGrpVal: String): TStringList; var i: integer; CurrGrpObject: TStringList; GrpPropVal: String; begin Result := nil; for i := 0 to Self.FGroupedObjects.Count - 1 do begin CurrGrpObject := TStringList(Self.FGroupedObjects[i]); GrpPropVal := GetGUIDFromStrings(CurrGrpObject, AGrpPropSN); if GrpPropVal = AGrpVal then begin Result := CurrGrpObject; Break; //// BREAK //// end; end; end; constructor TArchObjPropExp.Create; begin inherited; FPropsSN := TStringList.Create; FGroupPropsSN := TStringList.Create; FGroupedObjects := TObjectList.Create(true); FObjectPropsSN := TStringList.Create; FAllObjectPropsSN := TStringList.Create; FPropsCorrespond := TStringList.Create; end; destructor TArchObjPropExp.Destroy; var i: Integer; GrpObject: TStringList; begin FGroupPropsSN.Free; FObjectPropsSN.Free; FAllObjectPropsSN.Free; for i := 0 to FGroupedObjects.Count - 1 do begin GrpObject := TStringList(FGroupedObjects[i]); RemoveGUIDIDFromStrings(GrpObject, true); end; FGroupedObjects.Free; FreeStringsObjects(FPropsCorrespond, true); FPropsCorrespond.Free; inherited; end; procedure TArchObjPropExp.DefineAllProps; begin FAllObjectPropsSN.Clear; FAllObjectPropsSN.AddStrings(FPropsSN); FAllObjectPropsSN.AddStrings(FGroupPropsSN); FAllObjectPropsSN.AddStrings(FObjectPropsSN); end; { TArchExport } function StringListCompareAsFloat(List: TStringList; Index1, Index2: Integer): Integer; begin //Result := List.CompareStrings(List.FList^[Index1].FString, // List.FList^[Index2].FString); Result := CompareValue(StrToFloat_My(List[Index1]), StrToFloat_My(List[Index2])); end; // Добавить материал в остатки function TArchExport.AddMaterialToRemains(AMatType: Integer; AWidth, AHeight, ARemainsMinUseSize: Double; ACount: Integer): Boolean; var Key: String; GrpIdx: Integer; HeightObj: TStringList; HeightIdx: Integer; begin Result := false; if AHeight >= ARemainsMinUseSize then begin GrpIdx := GetMaterilaRemainsIndex(AMatType, AWidth, @Key); if GrpIdx = -1 then begin HeightObj := TStringList.Create; HeightObj.AddObject(FloatToStr(AHeight), TObject(ACount)); GrpIdx := FMaterilaRemains.AddObject(Key, HeightObj); end else begin HeightObj := TStringList(FMaterilaRemains.Objects[GrpIdx]); HeightIdx := HeightObj.IndexOf(FloatToStr(AHeight)); if HeightIdx = -1 then begin HeightObj.AddObject(FloatToStr(AHeight), TObject(ACount)); // Сортируем по Float HeightObj.CustomSort(StringListCompareAsFloat); end else HeightObj.Objects[HeightIdx] := TObject(Integer(HeightObj.Objects[HeightIdx]) + ACount); end; Result := true; end; end; procedure TArchExport.AddPropToKey(const APropSN, AVal: String; var AKey: String); begin if AKey <> '' then AKey := AKey + '|'; AKey := AKey + APropSN+'='+AVal; end; function TArchExport.CanUseRemainByPercent(ARemainsH, AMatHeight: Double): Boolean; begin Result := ARemainsH >= (AMatHeight * (Self.GetHeightPersentToRemains(AMatHeight) /100) ); end; function TArchExport.GetHeightPersentToRemains(AHeight: Double): Double; begin // за основу берем 30% для высоты материала 1м, // если высота больше то этот процент уменьшаем и наоборот - если высота меньше, то процент увеличиваем Result := 25 / (AHeight * 1/FScaleKoeff); end; function TArchExport.GetMaterilaRemainsIndex(AMatType: Integer; AWidth: Double; AKey: Pointer=nil): Integer; var Key: String; begin Key := ''; AddPropToKey(pnMaterialType, IntToStr(AMatType), Key); AddPropToKey(pnMaterialWidthUsable, FloatToStr(AWidth), Key); Result := FMaterilaRemains.IndexOf(Key); if AKey <> nil then String(AKey^) := Key; end; function TArchExport.RemoveMaterialFromRemains(AMatType: Integer; AWidth, AHeight, ARemainsMinUseSize: Double; ACount: Integer): Integer; var GrpIdx: Integer; HeightObj: TStringList; MatHeight: Double; MatCount: Integer; RemoveCount: Integer; MatHeightFree: Double; HaveRamains: Boolean; // Есть ли остатки в остатков i: Integer; begin //TmpCompon.Clear; //TmpCompon.AddProperty(0, '', dtInteger, biFalse, biFalse, biFalse, IntToStr(AMatType), '', pnMaterialType); //TmpCompon.AddPropertyValueAsFloat(pnMaterialWidthUsable, AWidth, true); //TmpCompon.AddPropertyValueAsFloat(pnMaterialHeightUsable, AHeight, true); //TmpCompon.AddPropertyValueAsFloat(pnCuttingWithRemains, ACount, true); //ExpArchObjPropToGrpObject(TmpCompon, FMaterilaRemainsGrp, true); Result := 0; GrpIdx := GetMaterilaRemainsIndex(AMatType, AWidth); if GrpIdx <> -1 then begin HeightObj := TStringList(FMaterilaRemains.Objects[GrpIdx]); while True do begin HaveRamains := false; i := 0; while i < HeightObj.Count do begin MatHeight := StrToFloat_My(HeightObj[i]); if MatHeight > AHeight then begin MatCount := Integer(HeightObj.Objects[i]); if MatCount > 0 then begin RemoveCount := ACount - Result; if RemoveCount > MatCount then RemoveCount := MatCount; HeightObj.Objects[i] := TObject(MatCount - RemoveCount); Result := Result + RemoveCount; MatHeightFree := MatHeight - AHeight; // Учитываем остатки от остатков //if Self.CanUseRemainByPercent(MatHeightFree, AMatHeight) then begin if Self.AddMaterialToRemains(AMatType, AWidth, MatHeightFree, ARemainsMinUseSize, RemoveCount) then HaveRamains := true; end; end; end; Inc(i); end; // остаемсяв цыкле если не вытянули нужное кол-во материала и были остатки из остатков //if Not((Result < ACount) and HaveRamains) then // Break; //// BREAK //// // Выходим из цыкла если вытянуто нужное кол-во остатков, или небыло остатков в остатков (условие выше будет работать аналогично) if (Result >= ACount) or Not HaveRamains then Break; //// BREAK //// end; end; end; procedure TArchExport.Clear; begin TmpCompon.Clear; //FMaterilaRemainsGrp.Clear; end; constructor TArchExport.Create; begin TmpCompon := TSCSComponent.Create(F_ProjMan); FMaterilaRemainsGrp := TArchObjPropExp.Create; FMaterilaRemainsGrp.FPropsSN.Add(pnCuttingWithRemains); // колво материала - суммируем FMaterilaRemainsGrp.FGroupPropsSN.Add(pnMaterialType); FMaterilaRemainsGrp.FGroupPropsSN.Add(pnMaterialWidthUsable); FMaterilaRemainsGrp.FGroupPropsSN.Add(pnMaterialHeightUsable); FMaterilaRemainsGrp.DefineAllProps; FMaterilaRemains := TStringList.Create; end; destructor TArchExport.Destroy; begin TmpCompon.Free; FMaterilaRemainsGrp.Free; FMaterilaRemains.Free; inherited; end; initialization if FigureClasses.IndexOf(TWallDivPath) = -1 then FigureClasses.Add(TWallDivPath); if FigureClasses.IndexOf(TRoomWallRect) = -1 then FigureClasses.Add(TRoomWallRect); //if FigureClasses.IndexOf(TBrickWallRect) = -1 then // FigureClasses.Add(TBrickWallRect); if FigureClasses.IndexOf(TWallPolyPath) = -1 then FigureClasses.Add(TWallPolyPath); end.