Punto de restauración.

This commit is contained in:
2025-07-31 09:58:38 +02:00
parent e1e1441892
commit 5db8f5439d
14 changed files with 1382 additions and 497 deletions

788
Civil/Fence/PVPlantFence.py Normal file
View File

@@ -0,0 +1,788 @@
# /**********************************************************************
# * *
# * Copyright (c) 2021 Javier Braña <javier.branagutierrez@gmail.com> *
# * *
# * This program is free software; you can redistribute it and/or modify*
# * it under the terms of the GNU Lesser General Public License (LGPL) *
# * as published by the Free Software Foundation; either version 2 of *
# * the License, or (at your option) any later version. *
# * for detail see the LICENCE text file. *
# * *
# * This program is distributed in the hope that it will be useful, *
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
# * GNU Library General Public License for more details. *
# * *
# * You should have received a copy of the GNU Library General Public *
# * License along with this program; if not, write to the Free Software *
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307*
# * USA *
# * *
# ***********************************************************************
import FreeCAD
import Part
import Draft
import MeshPart as mp
import ArchComponent
import Civil.Fence.PVPlantFencePost as PVPlantFencePost
import PVPlantSite
import Utils.PVPlantUtils as utils
import copy
import math
if FreeCAD.GuiUp:
import FreeCADGui
from PySide import QtCore, QtGui
from PySide.QtCore import QT_TRANSLATE_NOOP
import PySide.QtGui as QtGui
from pivy import coin
else:
# \cond
def translate(ctxt, txt):
return txt
def QT_TRANSLATE_NOOP(ctxt, txt):
return txt
# \endcond
try:
_fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
def _fromUtf8(s):
return s
import os
from PVPlantResources import DirIcons as DirIcons
EAST = FreeCAD.Vector(1, 0, 0)
def makePVPlantFence(section, post, path):
obj = FreeCAD.ActiveDocument.addObject('Part::FeaturePython', 'Fence')
Fence(obj)
obj.Post = post
obj.Base = path
if FreeCAD.GuiUp:
ViewProviderFence(obj.ViewObject)
hide(section)
hide(post)
hide(path)
try:
fende_group = FreeCAD.ActiveDocument.Fences
except:
fende_group = FreeCAD.ActiveDocument.addObject("App::DocumentObjectGroup", 'Fences')
fende_group.Label = "Fences"
FreeCAD.ActiveDocument.CivilGroup.addObject(fende_group)
fende_group.addObject(obj)
FreeCAD.ActiveDocument.recompute()
return obj
def hide(obj):
if hasattr(obj, 'ViewObject') and obj.ViewObject:
obj.ViewObject.Visibility = False
def get_parameter_from_v0_old(edge, offset):
""" Return parameter at distance offset from edge.Vertexes[0].sb method in Part.TopoShapeEdge??? """
import DraftVecUtils
lpt = edge.valueAt(edge.getParameterByLength(0))
vpt = edge.Vertexes[0].Point
if not DraftVecUtils.equals(vpt, lpt):
# this edge is flipped
length = edge.Length - offset
else:
# this edge is right way around
length = offset
return edge.getParameterByLength(length)
def get_parameter_from_v0(edge, offset):
"""Parámetro a distancia offset desde el primer vértice"""
lpt = edge.valueAt(edge.getParameterByLength(0))
vpt = edge.Vertexes[0].Point
if not vpt.isEqual(lpt, 1e-6):
return edge.getParameterByLength(edge.Length - offset)
return edge.getParameterByLength(offset)
def calculatePlacement(globalRotation, edge, offset, RefPt, xlate, align, normal=None):
placement = FreeCAD.Placement()
placement.Rotation = globalRotation
placement.move(RefPt + xlate)
if not align:
return placement
t = edge.tangentAt(get_parameter_from_v0(edge, offset)).normalize()
n = normal or FreeCAD.Vector(0, 0, 1)
b = t.cross(n).normalize()
# Asegurar sistema de coordenadas derecho
if n.dot(t.cross(b)) < 0:
b = -b
# Construir matriz
rotation_matrix = FreeCAD.Matrix(
t.x, b.x, n.x, 0,
t.y, b.y, n.y, 0,
t.z, b.z, n.z, 0,
0, 0, 0, 1
)
placement.Rotation = FreeCAD.Rotation(rotation_matrix)
return placement
def calculatePlacementsOnPath(shapeRotation, pathwire, count, xlate, align):
""" Calculates the placements of a shape along a given path so that each copy will be distributed evenly
- shapeRotation: rotation offset
- pathwire: path where place the shapes
- count: number of sections
- xlate: transformation offset
"""
import Part
import DraftGeomUtils
closedpath = DraftGeomUtils.isReallyClosed(pathwire)
normal = FreeCAD.Vector(0, 0, 1)
path = Part.__sortEdges__(pathwire.Edges)
ends = []
cdist = 0
# -----------------------------------------------------------------------------------------------------------------
totalEdges = len(path)
if not closedpath:
totalEdges -= 1
# -----------------------------------------------------------------------------------------------------------------
for e in path: # find cumulative edge end distance
cdist += e.Length
ends.append(cdist)
placements = []
# place the start shape
pt = path[0].Vertexes[0].Point
placements.append(calculatePlacement(shapeRotation, path[0], 0, pt, xlate, align, normal))
# closed path doesn't need shape on last vertex
if not closedpath:
# place the end shape
pt = path[-1].Vertexes[-1].Point
placements.append(calculatePlacement(shapeRotation, path[-1], path[-1].Length, pt, xlate, align, normal))
if count < 3:
return placements
# place the middle shapes
if closedpath:
stop = count
else:
stop = count - 1
step = float(cdist) / stop
travel = step
for i in range(1, stop):
# which edge in path should contain this shape?
# avoids problems with float math travel > ends[-1]
iend = len(ends) - 1
for j in range(0, len(ends)):
if travel <= ends[j]:
iend = j
break
# place shape at proper spot on proper edge
remains = ends[iend] - travel
offset = path[iend].Length - remains
pt = path[iend].valueAt(get_parameter_from_v0(path[iend], offset))
placements.append(calculatePlacement(shapeRotation, path[iend], offset, pt, xlate, align, normal))
travel += step
return placements
class Fence(ArchComponent.Component):
def __init__(self, obj):
ArchComponent.Component.__init__(self, obj)
self.setProperties(obj)
self.Posts = []
self.Foundations = []
# Does a IfcType exist?
# obj.IfcType = "Fence"
def setProperties(self, obj):
ArchComponent.Component.setProperties(self, obj)
pl = obj.PropertiesList
if not "Gate" in pl:
obj.addProperty("App::PropertyLinkList",
"Gate",
"Fence",
"A single fence post")
if not "Post" in pl:
obj.addProperty("App::PropertyLink",
"Post",
"Fence",
QT_TRANSLATE_NOOP("App::Property", "A single fence post"))
if not "Foundation" in pl:
obj.addProperty("App::PropertyLength",
"Foundation",
"Fence",
QT_TRANSLATE_NOOP("App::Property", "A single fence post"))
if not "Depth" in pl:
obj.addProperty("App::PropertyLength",
"Depth",
"Fence",
QT_TRANSLATE_NOOP("App::Property", "A single fence post")).Depth = 650
if not "Gap" in pl:
obj.addProperty("App::PropertyLength",
"Gap",
"Fence",
QT_TRANSLATE_NOOP("App::Property", "A single fence post")).Gap = 4000
if not "Angle" in pl:
obj.addProperty("App::PropertyAngle",
"Angle",
"Fence",
QT_TRANSLATE_NOOP("App::Property", "A single fence post")).Angle = 60
if not "MeshOffsetZ" in pl:
obj.addProperty("App::PropertyLength",
"MeshOffsetZ",
"Fence",
QT_TRANSLATE_NOOP("App::Property", "A single fence post")).MeshOffsetZ = 0
if not "MeshHeight" in pl:
obj.addProperty("App::PropertyLength",
"MeshHeight",
"Fence",
QT_TRANSLATE_NOOP("App::Property", "A single fence post")).MeshHeight = 2000
if not "Reinforce" in pl:
obj.addProperty("App::PropertyLength",
"Reinforce",
"Fence",
QT_TRANSLATE_NOOP("App::Property", "A single fence post")).Reinforce = 50000
########## Datos informativos:
if not "NumberOfSections" in pl:
obj.addProperty("App::PropertyQuantity",
"NumberOfSections",
"Output",
QT_TRANSLATE_NOOP("App::Property", "The number of sections the fence is built of"))
obj.setEditorMode("NumberOfSections", 1)
if not "NumberOfPosts" in pl:
obj.addProperty("App::PropertyQuantity",
"NumberOfPosts",
"Output",
QT_TRANSLATE_NOOP("App::Property", "The number of posts used to build the fence"))
obj.setEditorMode("NumberOfPosts", 1)
if not "Length" in pl:
obj.addProperty("App::PropertyLength",
"Length",
"Output",
QT_TRANSLATE_NOOP("App::Property", "The number of posts used to build the fence"))
obj.setEditorMode("Length", 1)
if not "Concrete" in pl:
obj.addProperty("App::PropertyVolume",
"Concrete",
"Output",
"Concrete Volume")
obj.setEditorMode("Concrete", 1)
if not "PlacementList" in pl:
obj.addProperty("App::PropertyPlacementList",
"PlacementList",
"Output",
QT_TRANSLATE_NOOP("App::Property", "The number of posts used to build the fence"))
obj.setEditorMode("Length", 1)
self.Type = "PVPlatFence"
def __getstate__(self):
if hasattr(self, 'sectionFaceNumbers'):
return (self.sectionFaceNumbers)
return None
def __setstate__(self, state):
if state is not None and isinstance(state, tuple):
self.sectionFaceNumbers = state[0]
return None
def execute(self, obj):
if not obj.Base or not obj.Post:
return
# 1. Preparar trazado base
pathwire = self.calculatePathWire(obj)
pathwire = utils.getProjected(pathwire, FreeCAD.Vector(0, 0, 1))
pathwire = utils.simplifyWire(pathwire)
if not pathwire or not pathwire.Edges:
return
# 2. Proyectar sobre terreno (con caché)
self.Posts = []
self.Foundations = []
site = PVPlantSite.get()
segments = mp.projectShapeOnMesh(pathwire, site.Terrain.Mesh, FreeCAD.Vector(0, 0, 1))
points=[]
for segment in segments:
points.extend(segment)
pathwire = Part.makePolygon(points)
if pathwire is None:
return
sectionLength = obj.Gap.Value
postLength = 0 #obj.Post.Diameter.Value #considerarlo 0 porque no influye
postPlacements = []
pathsegments = self.calculateSegments(obj, pathwire)
count = 0
drawFirstPost = True
pathLength = 0
for segment in pathsegments:
segwire = Part.Wire(Part.__sortEdges__(segment))
pathLength += segwire.Length
obj.NumberOfSections = self.calculateNumberOfSections(segwire.Length, sectionLength, postLength)
obj.NumberOfPosts = obj.NumberOfSections + 1
count += obj.NumberOfSections
downRotation = FreeCAD.Rotation(FreeCAD.Vector(1, 0, 0), -90)
placements = self.calculatePostPlacements(obj, segwire, downRotation)
if drawFirstPost:
drawFirstPost = False
else:
placements.pop(0)
postPlacements.extend(placements)
# 5. Generar geometría
postShapes, postFoundation = self.calculatePosts(obj, postPlacements)
mesh = self.calculate_sections(obj, postPlacements)
postShapes = Part.makeCompound(postShapes)
postFoundation = Part.makeCompound(postFoundation)
# 6. Crear forma final
obj.Shape = Part.makeCompound([postShapes, postFoundation, mesh])
# 7. Actualizar propiedades
obj.NumberOfSections = count
obj.NumberOfPosts = count + 1
obj.Length = pathLength
obj.Concrete = count * postFoundation.SubShapes[0].Volume
def calculateSegments(self, obj, pathwire):
''' Calcular los segmentos de la ruta '''
import math
segments = []
segment = [pathwire.Edges[0]]
segments.append(segment)
for ind in range(len(pathwire.Edges) - 1):
ed1 = pathwire.Edges[ind]
ed2 = pathwire.Edges[ind + 1]
vec1 = ed1.Vertexes[1].Point - ed1.Vertexes[0].Point
vec2 = ed2.Vertexes[1].Point - ed2.Vertexes[0].Point
angle = math.degrees(vec1.getAngle(vec2))
if angle > obj.Angle.Value:
segment = []
segments.append(segment)
segment.append(ed2)
return segments
def calculateNumberOfSections(self, pathLength, sectionLength, postLength):
withoutLastPost = pathLength - postLength
realSectionLength = sectionLength + postLength
return math.ceil(withoutLastPost / realSectionLength)
def calculatePostPlacements(self, obj, pathwire, rotation):
postWidth = obj.Post.Diameter.Value
transformationVector = FreeCAD.Vector(0, - postWidth / 2, 0)
placements = calculatePlacementsOnPath(rotation, pathwire, int(obj.NumberOfSections) + 1, transformationVector, True)
# The placement of the last object is always the second entry in the list.
# So we move it to the end:
if len(placements) > 1:
placements.append(placements.pop(1))
return placements
def calculatePosts(self, obj, postPlacements):
posts = []
foundations = []
for placement in postPlacements:
new_post = obj.Post.Shape.copy()
new_post = Part.Solid(new_post)
new_post.Placement = placement
new_post.Placement.Base.z += 100
posts.append(new_post)
foundation = Part.makeCylinder(150, 700)
foundation.Placement = placement
foundation.Placement.Base.z -= obj.Depth.Value
#foundation = foundation.cut(new_post)
foundations.append(foundation)
return posts, foundations
def calculate_sections(self, obj, postPlacements):
offsetz = FreeCAD.Vector(0, 0, obj.MeshOffsetZ.Value)
meshHeight = FreeCAD.Vector(0, 0, obj.MeshHeight.Value)
points_down = []
points_up = []
for i in range(len(postPlacements) - 1):
p1 = postPlacements[i].Base + offsetz
p2 = postPlacements[i + 1].Base + offsetz
p3 = p1 + meshHeight
p4 = p2 + meshHeight
points_down.extend([p1, p2])
points_up.extend([p3, p4])
shape = Part.makeRuledSurface(Part.makePolygon(points_down), Part.makePolygon(points_up))
return shape
def calculatePathWire(self, obj):
if obj.Base:
wire = None
if hasattr(obj.Base.Shape, 'Wires') and obj.Base.Shape.Wires:
wire = obj.Base.Shape.Wires[0]
elif obj.Base.Shape.Edges:
wire = Part.Wire(obj.Base.Shape.Edges)
return wire
return None
class ViewProviderFence(ArchComponent.ViewProviderComponent):
"A View Provider for the Fence object"
def __init__(self, vobj):
ArchComponent.ViewProviderComponent.__init__(self, vobj)
vobj.Proxy = self
#vobj.addExtension("Gui::ViewProviderGroupExtensionPython")
def getIcon(self):
return str(os.path.join(DirIcons, "fence.svg"))
def attach(self, vobj):
'''
Create Object visuals in 3D view.
'''
self.Object = vobj.Object
# GeoCoords Node.
self.geo_coords = coin.SoGeoCoordinate()
# Surface features.
self.triangles = coin.SoIndexedFaceSet()
self.face_material = coin.SoMaterial()
self.edge_material = coin.SoMaterial()
self.edge_color = coin.SoBaseColor()
self.edge_style = coin.SoDrawStyle()
self.edge_style.style = coin.SoDrawStyle.LINES
shape_hints = coin.SoShapeHints()
shape_hints.vertex_ordering = coin.SoShapeHints.COUNTERCLOCKWISE
mat_binding = coin.SoMaterialBinding()
mat_binding.value = coin.SoMaterialBinding.PER_FACE
offset = coin.SoPolygonOffset()
# Face root.
faces = coin.SoSeparator()
faces.addChild(shape_hints)
faces.addChild(self.face_material)
faces.addChild(mat_binding)
faces.addChild(self.geo_coords)
faces.addChild(self.triangles)
# Highlight for selection.
highlight = coin.SoType.fromName('SoFCSelection').createInstance()
highlight.style = 'EMISSIVE_DIFFUSE'
faces.addChild(shape_hints)
highlight.addChild(self.edge_material)
highlight.addChild(mat_binding)
highlight.addChild(self.edge_style)
highlight.addChild(self.geo_coords)
highlight.addChild(self.triangles)
def updateData(self, obj, prop):
'''
Update Object visuals when a data property changed.
'''
origin = PVPlantSite.get()
base = copy.deepcopy(origin.Origin)
base.z = 0
#print(" - Propiedad: ", prop)
if prop == "Shape":
shape = obj.getPropertyByName(prop)
# Get GeoOrigin.
points = [ver.Point for ver in shape.Vertexes]
# Set GeoCoords.
geo_system = ["UTM", origin.UtmZone, "FLAT"]
self.geo_coords.geoSystem.setValues(geo_system)
self.geo_coords.point.values = points
def claimChildren(self):
children = []
if self.Object.Post:
children.append(self.Object.Post)
if self.Object.Base:
children.append(self.Object.Base)
if self.Object.Gate:
children.append(self.Object.Gate)
return children
class FenceTaskPanel:
'''The TaskPanel to setup the fence'''
def __init__(self):
self.section = None
self.post = None
self.path = None
# form: -----------------------------------------------------------------------------------
self.formFence = QtGui.QWidget()
self.formFence.resize(800, 640)
self.formFence.setWindowTitle("Fence setup")
self.formFence.setWindowIcon(QtGui.QIcon(os.path.join(DirIcons, "contours.svg")))
self.grid = QtGui.QGridLayout(self.formFence)
# parameters
self.labelPath = QtGui.QLabel()
self.labelPath.setText("Recorrido:")
self.linePath = QtGui.QLineEdit(self.formFence)
self.linePath.setObjectName(_fromUtf8("lineEdit1"))
self.linePath.readOnly = True
self.grid.addWidget(self.labelPath, self.grid.rowCount(), 0, 1, 1)
self.grid.addWidget(self.linePath, self.grid.rowCount() - 1, 1, 1, 1)
self.buttonPathSelect = QtGui.QPushButton('Add')
self.grid.addWidget(self.buttonPathSelect, self.grid.rowCount() - 1, 2, 1, 1)
self.line1 = QtGui.QFrame()
self.line1.setFrameShape(QtGui.QFrame.HLine)
self.line1.setFrameShadow(QtGui.QFrame.Sunken)
self.grid.addWidget(self.line1, self.grid.rowCount(), 0, 1, -1)
self.label = QtGui.QLabel()
self.label.setText("Separación entre apoyos:")
self.grid.addWidget(self.label, self.grid.rowCount(), 0, 1, -1)
self.labelInterval = QtGui.QLabel()
self.labelInterval.setText("Intervalo:")
self.valueInterval = FreeCADGui.UiLoader().createWidget("Gui::InputField")
self.valueInterval.setText("4,0 m")
self.grid.addWidget(self.labelInterval, self.grid.rowCount(), 0, 1, 1)
self.grid.addWidget(self.valueInterval, self.grid.rowCount() - 1, 1, 1, 2)
self.line1 = QtGui.QFrame()
self.line1.setFrameShape(QtGui.QFrame.HLine)
self.line1.setFrameShadow(QtGui.QFrame.Sunken)
self.grid.addWidget(self.line1, self.grid.rowCount(), 0, 1, -1)
self.label = QtGui.QLabel()
self.label.setText("Mayado:")
self.grid.addWidget(self.label, self.grid.rowCount(), 0, 1, -1)
self.labelHeight = QtGui.QLabel()
self.labelHeight.setText("Altura:")
self.valueHeight = FreeCADGui.UiLoader().createWidget("Gui::InputField")
self.valueHeight.setText("2 m")
self.grid.addWidget(self.labelHeight, self.grid.rowCount(), 0, 1, 1)
self.grid.addWidget(self.valueHeight, self.grid.rowCount() - 1, 1, 1, 2)
self.labelOffset = QtGui.QLabel()
self.labelOffset.setText("Separación del suelo:")
self.valueOffset = FreeCADGui.UiLoader().createWidget("Gui::InputField")
self.valueOffset.setText("0 m")
self.grid.addWidget(self.labelOffset, self.grid.rowCount(), 0, 1, 1)
self.grid.addWidget(self.valueOffset, self.grid.rowCount() - 1, 1, 1, 2)
self.buttonPathSelect.clicked.connect(self.addPath)
self.valueInterval.valueChanged.connect(self.SetupGrid)
self.valueHeight.valueChanged.connect(self.SetupGrid)
# self.valueDepth.valueChanged.connect(self.SetupPost)
# Form para configurar el poste: -------------------------------------------------------------------
self.formPost = QtGui.QWidget()
self.formPost.resize(800, 640)
self.formPost.setWindowTitle("Post setup")
self.formPost.setWindowIcon(QtGui.QIcon(os.path.join(DirIcons, "contours.svg")))
self.grid = QtGui.QGridLayout(self.formPost)
# parameters
self.labelDiameter = QtGui.QLabel()
self.labelDiameter.setText("Diámetro:")
self.valueDiameter = FreeCADGui.UiLoader().createWidget("Gui::InputField")
self.valueDiameter.setText("48 mm")
self.grid.addWidget(self.labelDiameter, self.grid.rowCount(), 0, 1, 1)
self.grid.addWidget(self.valueDiameter, self.grid.rowCount() - 1, 1, 1, 1)
self.labelLength = QtGui.QLabel()
self.labelLength.setText("Longitud:")
self.valueLength = FreeCADGui.UiLoader().createWidget("Gui::InputField")
self.valueLength.setText("3,0 m")
self.grid.addWidget(self.labelLength, self.grid.rowCount(), 0, 1, 1)
self.grid.addWidget(self.valueLength, self.grid.rowCount() - 1, 1, 1, 1)
self.labelDepth = QtGui.QLabel()
self.labelDepth.setText("Profundidad:")
self.valueDepth = FreeCADGui.UiLoader().createWidget("Gui::InputField")
self.valueDepth.setText("700,0 mm")
self.grid.addWidget(self.labelDepth, self.grid.rowCount(), 0, 1, 1)
self.grid.addWidget(self.valueDepth, self.grid.rowCount() - 1, 1, 1, 1)
self.valueDiameter.valueChanged.connect(self.SetupPost)
self.valueLength.valueChanged.connect(self.SetupPost)
self.valueDepth.valueChanged.connect(self.SetupPost)
# Form para configurar la zapata: ----------------------------------------------------------
self.formFoundation = QtGui.QWidget()
self.formFoundation.resize(800, 640)
self.formFoundation.setWindowTitle("Post setup")
self.formFoundation.setWindowIcon(QtGui.QIcon(os.path.join(DirIcons, "contours.svg")))
self.grid = QtGui.QGridLayout(self.formFoundation)
# parameters
self.labelFoundationDiameter = QtGui.QLabel()
self.labelFoundationDiameter.setText("Cimentación:")
self.grid.addWidget(self.labelFoundationDiameter, self.grid.rowCount(), 0, 1, 1)
self.labelFoundationDiameter = QtGui.QLabel()
self.labelFoundationDiameter.setText("Diámetro:")
self.valueFoundationDiameter = FreeCADGui.UiLoader().createWidget("Gui::InputField")
self.valueFoundationDiameter.setText("200,0 mm")
self.grid.addWidget(self.labelFoundationDiameter, self.grid.rowCount(), 0, 1, 1)
self.grid.addWidget(self.valueFoundationDiameter, self.grid.rowCount() - 1, 1, 1, 1)
self.labelFoundationDepth = QtGui.QLabel()
self.labelFoundationDepth.setText("Profundidad:")
self.valueFoundationDepth = FreeCADGui.UiLoader().createWidget("Gui::InputField")
self.valueFoundationDepth.setText("700,0 mm")
self.grid.addWidget(self.labelFoundationDepth, self.grid.rowCount(), 0, 1, 1)
self.grid.addWidget(self.valueFoundationDepth, self.grid.rowCount() - 1, 1, 1, 1)
self.form = [self.formFence, self.formPost, self.formFoundation]
# valores iniciales y creación del la valla:
self.post = PVPlantFencePost.makeFencePost()
self.post.Label = "Post"
FreeCAD.ActiveDocument.recompute()
self.fence = makePVPlantFence(self.section, self.post, self.path)
def addPath(self):
sel = FreeCADGui.Selection.getSelection()
if len(sel) > 0:
self.path = sel[0]
self.linePath.setText(self.path.Label)
self.fence.Base = self.path
FreeCAD.ActiveDocument.recompute()
def SetupPost(self):
if self.post.Diameter != FreeCAD.Units.Quantity(self.valueDiameter.text()).Value:
self.post.Diameter = FreeCAD.Units.Quantity(self.valueDiameter.text()).Value
if self.post.Length != FreeCAD.Units.Quantity(self.valueLength.text()).Value:
self.post.Length = FreeCAD.Units.Quantity(self.valueLength.text()).Value
if self.post.Placement.Base.z != -FreeCAD.Units.Quantity(self.valueDepth.text()).Value:
self.post.Placement.Base.z = -FreeCAD.Units.Quantity(self.valueDepth.text()).Value
self.fence.Depth = FreeCAD.Units.Quantity(self.valueDepth.text()).Value
FreeCAD.ActiveDocument.recompute()
def SetupGrid(self):
return
if self.path.End.x != FreeCAD.Units.Quantity(self.valueInterval.text()).Value:
self.path.End.x = FreeCAD.Units.Quantity(self.valueInterval.text()).Value
if self.section.LengthFwd != FreeCAD.Units.Quantity(self.valueHeight.text()).Value:
self.section.LengthFwd = FreeCAD.Units.Quantity(self.valueHeight.text()).Value
FreeCAD.ActiveDocument.recompute()
def makeGrid(self):
return None
import Draft
p1 = FreeCAD.Vector(0, 0, 0)
p2 = FreeCAD.Vector(4000, 0, 0)
line = Draft.makeLine(p1, p2)
section = FreeCAD.ActiveDocument.addObject('Part::Extrusion', 'Extrude')
section.Base = line
section.DirMode = "Custom"
section.Dir = FreeCAD.Vector(0.0, 0.0, 1.0)
section.DirLink = None
section.LengthFwd = 2000.0
section.LengthRev = 0.0
section.Solid = False
section.Reversed = False
section.Symmetric = False
section.TaperAngle = 0.0
section.TaperAngleRev = 0.0
line.Visibility = False
return section
# Commands ---------------------------------------------------------------------------------
class CommandPVPlantFence:
"the PVPlant Fence command definition"
def GetResources(self):
return {'Pixmap': str(os.path.join(DirIcons, "fence.svg")),
'Accel': "C, F",
'MenuText': QT_TRANSLATE_NOOP("PVPlantFence", "Fence"),
'ToolTip': QT_TRANSLATE_NOOP("PVPlantFence",
"Creates a fence object from a selected section, post and path")}
def IsActive(self):
return not FreeCAD.ActiveDocument is None
def Activated(self):
self.TaskPanel = FenceTaskPanel()
FreeCADGui.Control.showDialog(self.TaskPanel)
if FreeCAD.GuiUp:
class CommandFenceGroup:
def GetCommands(self):
return tuple(['PVPlantFence',
'PVPlantGate',
'PVPlantFencePost'
])
def GetResources(self):
return {'MenuText': QT_TRANSLATE_NOOP("", 'PVPlantFence'),
'ToolTip': QT_TRANSLATE_NOOP("", 'PVPlantFence')
}
def IsActive(self):
site = FreeCAD.ActiveDocument.getObject("Site")
return (not (FreeCAD.ActiveDocument is None) and
not (site is None) and
not (site.Terrain is None))
import Civil.Fence.PVPlantFenceGate as PVPlantFenceGate
FreeCADGui.addCommand('PVPlantFence', CommandPVPlantFence())
FreeCADGui.addCommand('PVPlantGate', PVPlantFenceGate.CommandPVPlantGate())
FreeCADGui.addCommand('PVPlantFencePost', PVPlantFencePost.CommandFencePost())
#FreeCADGui.addCommand('PVPlantFenceGroup', CommandFenceGroup())

768
Civil/Fence/PVPlantFence.ui Normal file
View File

@@ -0,0 +1,768 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>formRack</class>
<widget class="QDialog" name="formRack">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>476</width>
<height>641</height>
</rect>
</property>
<property name="windowTitle">
<string>Fixed Frame:</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="leftMargin">
<number>5</number>
</property>
<property name="topMargin">
<number>5</number>
</property>
<property name="rightMargin">
<number>5</number>
</property>
<property name="bottomMargin">
<number>5</number>
</property>
<item>
<widget class="QGroupBox" name="groupBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="title">
<string>Configuración de la valla</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<property name="leftMargin">
<number>5</number>
</property>
<property name="topMargin">
<number>5</number>
</property>
<property name="rightMargin">
<number>5</number>
</property>
<property name="bottomMargin">
<number>5</number>
</property>
<property name="horizontalSpacing">
<number>5</number>
</property>
<property name="verticalSpacing">
<number>2</number>
</property>
<item row="0" column="2">
<widget class="QPushButton" name="pushButton">
<property name="text">
<string>Add</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QDoubleSpinBox" name="editModuleLenght">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>140</width>
<height>0</height>
</size>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buttonSymbols">
<enum>QAbstractSpinBox::NoButtons</enum>
</property>
<property name="decimals">
<number>3</number>
</property>
<property name="maximum">
<double>5.000000000000000</double>
</property>
<property name="singleStep">
<double>0.010000000000000</double>
</property>
<property name="value">
<double>0.960000000000000</double>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_10">
<property name="text">
<string>Separación entre apoyos (m)</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_9">
<property name="text">
<string>Recorrido:</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Configuración del poste</string>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<item row="3" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Columnas (un)</string>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QDoubleSpinBox" name="editFrontHeight">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>140</width>
<height>0</height>
</size>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buttonSymbols">
<enum>QAbstractSpinBox::NoButtons</enum>
</property>
<property name="maximum">
<double>5.000000000000000</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
<property name="value">
<double>0.800000000000000</double>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Orientación del módulo</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QDoubleSpinBox" name="editVerticalGap">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>140</width>
<height>0</height>
</size>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buttonSymbols">
<enum>QAbstractSpinBox::NoButtons</enum>
</property>
<property name="maximum">
<double>0.900000000000000</double>
</property>
<property name="singleStep">
<double>0.010000000000000</double>
</property>
<property name="value">
<double>0.020000000000000</double>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QSpinBox" name="editRows">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>140</width>
<height>0</height>
</size>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buttonSymbols">
<enum>QAbstractSpinBox::NoButtons</enum>
</property>
<property name="minimum">
<number>1</number>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="comboFrameType">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>140</width>
<height>0</height>
</size>
</property>
<item>
<property name="text">
<string>Fija</string>
</property>
</item>
<item>
<property name="text">
<string>Tracker 1 Eje</string>
</property>
</item>
</widget>
</item>
<item row="7" column="1">
<widget class="QDoubleSpinBox" name="editLeftOffset">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>140</width>
<height>0</height>
</size>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buttonSymbols">
<enum>QAbstractSpinBox::NoButtons</enum>
</property>
<property name="maximum">
<double>0.900000000000000</double>
</property>
<property name="singleStep">
<double>0.010000000000000</double>
</property>
<property name="value">
<double>0.050000000000000</double>
</property>
</widget>
</item>
<item row="12" column="0">
<widget class="QLabel" name="label_18">
<property name="text">
<string>Offset borde derecha (m)</string>
</property>
</widget>
</item>
<item row="14" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Ángulo de inclinación (º)</string>
</property>
</widget>
</item>
<item row="12" column="1">
<widget class="QDoubleSpinBox" name="editRightOffset">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>140</width>
<height>0</height>
</size>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buttonSymbols">
<enum>QAbstractSpinBox::NoButtons</enum>
</property>
<property name="maximum">
<double>0.900000000000000</double>
</property>
<property name="singleStep">
<double>0.010000000000000</double>
</property>
<property name="value">
<double>0.050000000000000</double>
</property>
</widget>
</item>
<item row="14" column="1">
<widget class="QSpinBox" name="editTilt">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>140</width>
<height>0</height>
</size>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buttonSymbols">
<enum>QAbstractSpinBox::NoButtons</enum>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>60</number>
</property>
</widget>
</item>
<item row="15" column="1">
<widget class="QSpinBox" name="editInclination">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>140</width>
<height>0</height>
</size>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buttonSymbols">
<enum>QAbstractSpinBox::NoButtons</enum>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>60</number>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Filas (un)</string>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Distancia al suelo en el frente (m)</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QSpinBox" name="editCols">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>140</width>
<height>0</height>
</size>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buttonSymbols">
<enum>QAbstractSpinBox::NoButtons</enum>
</property>
<property name="minimum">
<number>20</number>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="labelVerticalGap">
<property name="text">
<string>Separación vertical entre módulos (m)</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="comboModuleOrientation">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>140</width>
<height>0</height>
</size>
</property>
<item>
<property name="text">
<string>Landscape</string>
</property>
</item>
<item>
<property name="text">
<string>Portrait</string>
</property>
</item>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Separación horizontal entre módulos (m)</string>
</property>
</widget>
</item>
<item row="15" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Ängulo máximo de inclinación longitudinal (ª)</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QDoubleSpinBox" name="editHorizontalGap">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>140</width>
<height>0</height>
</size>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buttonSymbols">
<enum>QAbstractSpinBox::NoButtons</enum>
</property>
<property name="maximum">
<double>0.900000000000000</double>
</property>
<property name="singleStep">
<double>0.010000000000000</double>
</property>
<property name="value">
<double>0.020000000000000</double>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Tipo de estructura</string>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QLabel" name="label_17">
<property name="text">
<string>Offset borde izquierda (m)</string>
</property>
</widget>
</item>
<item row="16" column="0" colspan="2">
<widget class="QWidget" name="widgetTracker" native="true">
<layout class="QGridLayout" name="gridLayout_4">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<property name="spacing">
<number>5</number>
</property>
<item row="2" column="0">
<widget class="QLabel" name="labelVerticalGap_2">
<property name="text">
<string>Separación entre uniones (m)</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QCheckBox" name="checkBox">
<property name="text">
<string>Separación Motor (m)</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QSpinBox" name="editInternalGapNumber">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>140</width>
<height>0</height>
</size>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buttonSymbols">
<enum>QAbstractSpinBox::NoButtons</enum>
</property>
<property name="minimum">
<number>0</number>
</property>
<property name="maximum">
<number>6</number>
</property>
<property name="value">
<number>0</number>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_19">
<property name="text">
<string>Número de uniones</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QDoubleSpinBox" name="editInternalGap">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>140</width>
<height>0</height>
</size>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buttonSymbols">
<enum>QAbstractSpinBox::NoButtons</enum>
</property>
<property name="maximum">
<double>0.900000000000000</double>
</property>
<property name="singleStep">
<double>0.010000000000000</double>
</property>
<property name="value">
<double>0.020000000000000</double>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QDoubleSpinBox" name="editMotorGap">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>140</width>
<height>0</height>
</size>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buttonSymbols">
<enum>QAbstractSpinBox::NoButtons</enum>
</property>
<property name="maximum">
<double>0.900000000000000</double>
</property>
<property name="singleStep">
<double>0.010000000000000</double>
</property>
<property name="value">
<double>0.020000000000000</double>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_3">
<property name="title">
<string>Cimentación</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QLabel" name="label_13">
<property name="text">
<string>Total de módulos</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="editTotalModules">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>140</width>
<height>0</height>
</size>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_14">
<property name="text">
<string>Potencia total (wp)</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="editTotalPower">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>140</width>
<height>0</height>
</size>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_15">
<property name="text">
<string>Longitud (m)</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="editTotalLength">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>140</width>
<height>0</height>
</size>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_16">
<property name="text">
<string>Anchura (m)</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLineEdit" name="editTotalWidth">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>140</width>
<height>0</height>
</size>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@@ -0,0 +1,427 @@
# /**********************************************************************
# * *
# * Copyright (c) 2021 Javier Braña <javier.branagutierrez@gmail.com> *
# * *
# * This program is free software; you can redistribute it and/or modify*
# * it under the terms of the GNU Lesser General Public License (LGPL) *
# * as published by the Free Software Foundation; either version 2 of *
# * the License, or (at your option) any later version. *
# * for detail see the LICENCE text file. *
# * *
# * This program is distributed in the hope that it will be useful, *
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
# * GNU Library General Public License for more details. *
# * *
# * You should have received a copy of the GNU Library General Public *
# * License along with this program; if not, write to the Free Software *
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307*
# * USA *
# * *
# ***********************************************************************
import ArchComponent
import FreeCAD
import Part
if FreeCAD.GuiUp:
import FreeCADGui
from PySide import QtCore, QtGui, QtSvg
from PySide.QtCore import QT_TRANSLATE_NOOP
import PySide.QtGui as QtGui
import draftguitools.gui_trackers as DraftTrackers
else:
# \cond
def translate(ctxt, txt):
return txt
def QT_TRANSLATE_NOOP(ctxt, txt):
return txt
# \endcond
try:
_fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
def _fromUtf8(s):
return s
import os
import PVPlantResources
from PVPlantResources import DirIcons as DirIcons
def makePVPlantFence():
obj = FreeCAD.ActiveDocument.addObject('Part::FeaturePython', 'FenceGate')
FenceGate(obj)
if FreeCAD.GuiUp:
ViewProviderGate(obj.ViewObject)
return obj
class FenceGate(ArchComponent.Component):
def __init__(self, obj):
ArchComponent.Component.__init__(self, obj)
self.setProperties(obj)
def setProperties(self, obj):
pl = obj.PropertiesList
if not ("GateType" in pl):
obj.addProperty("App::PropertyEnumeration",
"GateType",
"Gate",
QT_TRANSLATE_NOOP("App::Property",
"The facemaker type to use to build the profile of this object")
).GateType = ["Single", "Double"]
if not ("GateWidth" in pl):
obj.addProperty("App::PropertyDistance",
"GateWidth",
"Gate",
"Base wire"
).GateWidth = 3000
if not ("GateHeight" in pl):
obj.addProperty("App::PropertyDistance",
"GateHeight",
"Gate",
"Base wire"
).GateHeight = 2000
if not ("PostWidth" in pl):
obj.addProperty("App::PropertyDistance",
"PostWidth",
"Gate",
"Base wire"
).PostWidth = 60
if not ("PostHeight" in pl):
obj.addProperty("App::PropertyDistance",
"PostHeight",
"Gate",
"Base wire"
).PostHeight = 2000
if not "PostDepth" in pl:
obj.addProperty("App::PropertyLength",
"PostDepth",
"Fence",
"A single fence post").PostDepth = 700
self.Type = "PVPlatFenceGate"
#obj.Type = self.Type
obj.Proxy = self
self.obj = obj
def __getstate__(self):
if hasattr(self, 'sectionFaceNumbers'):
return (self.sectionFaceNumbers)
return None
def __setstate__(self, state):
if state is not None and isinstance(state, tuple):
self.sectionFaceNumbers = state[0]
return None
def onDocumentRestored(self, obj):
"""Method run when the document is restored."""
self.setProperties(obj)
def onChanged(self, obj, prop):
'''Do something when a property has changed'''
def execute(self, obj):
tubewidth = 50
gap = 20
posts = Part.makeCompound([])
gates = Part.makeCompound([])
pl = obj.Placement
post = Part.makeBox(obj.PostWidth.Value,
obj.PostWidth.Value,
obj.PostHeight.Value + obj.PostDepth.Value)
gate = Part.makeBox(obj.GateWidth.Value,
tubewidth,
obj.GateHeight.Value)
cut = Part.makeBox(obj.GateWidth.Value - tubewidth * 2,
tubewidth,
obj.GateHeight.Value - tubewidth * 2)
cut.Placement.Base += FreeCAD.Vector(tubewidth, 0, tubewidth)
gate = gate.cut(cut)
if obj.GateType == "Single":
post.Placement.Base = FreeCAD.Vector(-(obj.PostWidth.Value + gap + obj.GateWidth.Value / 2),
-obj.PostWidth.Value / 2,
-obj.PostDepth.Value)
posts.add(post)
post = post.copy()
post.Placement.Base.x = -(post.Placement.Base.x + obj.PostWidth.Value)
posts.add(post)
gate.Placement.Base += FreeCAD.Vector(-obj.GateWidth.Value / 2,
obj.PostWidth.Value / 2 - tubewidth,
0)
gates.add(gate)
else:
post.Placement.Base = FreeCAD.Vector(-(obj.PostWidth.Value + gap * 1.5 + obj.GateWidth.Value),
-obj.PostWidth.Value / 2,
-obj.PostDepth.Value)
posts.add(post)
post = post.copy()
post.Placement.Base.x = -(post.Placement.Base.x + obj.PostWidth.Value)
posts.add(post)
gate.Placement.Base += FreeCAD.Vector(-(obj.GateWidth.Value + gap * 0.5),
obj.PostWidth.Value / 2 - tubewidth,
0)
gates.add(gate)
gate = gate.copy()
gate.Placement.Base.x = gap * 0.5
gates.add(gate)
obj.Shape = Part.makeCompound([gates, posts])
obj.Placement = pl
class ViewProviderGate:
def __init__(self, vobj):
''' Set view properties. '''
vobj.Proxy = self
def attach(self, vobj):
self.Object = vobj.Object
def getIcon(self):
''' Return object treeview icon. '''
return str(os.path.join(DirIcons, "gate.svg"))
def claimChildren(self):
""" Provides object grouping """
children = []
if self.Object.Base:
children.append(self.Object.Base)
return children
class CommandPVPlantGate:
"the PVPlant Fence command definition"
def __init__(self):
''' p = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Arch")
self.Thickness = p.GetFloat("WindowThickness", 50)
self.Width = p.GetFloat("WindowWidth", 1000)
self.Height = p.GetFloat("DoorHeight", 2100)'''
self.Width = 0
self.Height = 0
self.Length = 0
self.tracker = None
def GetResources(self):
return {'Pixmap': str(os.path.join(DirIcons, "gate.svg")),
'Accel': "C, F",
'MenuText': QT_TRANSLATE_NOOP("PVPlantFence", "Gate"),
'ToolTip': QT_TRANSLATE_NOOP("PVPlantFence",
"Creates a fence object from a selected section, post and path")}
def IsActive(self):
return not FreeCAD.ActiveDocument is None
def Activated(self):
self.tracker = DraftTrackers.boxTracker()
self.tracker.length(self.Length)
self.tracker.width(self.Width)
self.tracker.height(self.Height)
self.tracker.on()
FreeCAD.Console.PrintMessage("Choose a face on an existing object or select a preset" + "\n")
FreeCADGui.Snapper.getPoint(callback=self.getPoint,
movecallback=self.update,
extradlg=self.taskbox())
def getPoint(self, point=None, obj=None):
"this function is called by the snapper when it has a 3D point"
if obj.Name[:5] == "Fence":
self.tracker.finalize()
if point is None:
return
ver = Part.Vertex(point)
dist = ver.distToShape(obj.Base.Shape)
point1 = dist[1][0][1]
ed = None
if dist[2][0][3] == "Edge":
ed = obj.Base.Shape.Edges[int(dist[-1][0][4])]
vec = ed.Vertexes[1].Point.sub(ed.Vertexes[0].Point)
FreeCAD.ActiveDocument.openTransaction("Create Gate")
gate = makePVPlantFence()
try:
import MeshPart as mp
import PVPlantSite
site = PVPlantSite.get()
point1 = mp.projectPointsOnMesh([point1,], site.Terrain.Mesh, FreeCAD.Vector(0, 0, 1))[0]
except:
FreeCAD.Console.PrintError("No se puede encontrar punto 3D.." + "\n")
pass
gate.Placement.Base = point1
gate.Placement.Rotation = FreeCAD.Rotation(FreeCAD.Vector(-1, 0, 0), vec)
tmp = obj.Gate
tmp.append(gate)
obj.Gate = tmp
FreeCAD.ActiveDocument.commitTransaction()
FreeCAD.ActiveDocument.recompute()
return
else:
FreeCADGui.Snapper.getPoint(callback=self.getPoint,
movecallback=self.update,
extradlg=self.taskbox())
def update(self, point, info):
''' this function is called by the Snapper when the mouse is moved '''
delta = FreeCAD.Vector(self.Length / 2, self.Width / 2, self.Height / 2)
rot = FreeCAD.Rotation()
#self.tracker.setRotation(rot)
self.tracker.pos(point)
return
delta = FreeCAD.Vector(self.Length / 2, self.Width / 2, self.Height / 2)
delta = delta.add(FreeCAD.Vector(0, 0, self.Sill))
rot = FreeCAD.Rotation()
if info:
if "Face" in info['Component']:
import WorkingPlane
o = FreeCAD.ActiveDocument.getObject(info['Object'])
self.baseFace = [o, int(info['Component'][4:]) - 1]
# print("switching to ",o.Label," face ",self.baseFace[1])
f = o.Shape.Faces[self.baseFace[1]]
p = WorkingPlane.getPlacementFromFace(f, rotated=True)
if p:
rot = p.Rotation
self.tracker.setRotation(rot)
r = self.tracker.trans.rotation.getValue().getValue()
if r != (0, 0, 0, 1):
delta = FreeCAD.Rotation(r[0], r[1], r[2], r[3]).multVec(FreeCAD.Vector(delta.x, -delta.y, -delta.z))
self.tracker.pos(point.add(delta))
def taskbox(self):
"sets up a taskbox widget"
w = FreeCADGui.PySideUic.loadUi(PVPlantResources.__dir__ + "/PVPlantFenceGate.ui")
self.Width = 80
self.Height = 2000
self.Length = 6146
return w
w = QtGui.QWidget()
ui = FreeCADGui.UiLoader()
w.setWindowTitle("Window options")
grid = QtGui.QGridLayout(w)
# include box
include = QtGui.QCheckBox(translate("Arch","Auto include in host object"))
include.setChecked(True)
grid.addWidget(include,0,0,1,2)
QtCore.QObject.connect(include,QtCore.SIGNAL("stateChanged(int)"),self.setInclude)
# sill height
labels = QtGui.QLabel(translate("Arch","Sill height"))
values = ui.createWidget("Gui::InputField")
grid.addWidget(labels,1,0,1,1)
grid.addWidget(values,1,1,1,1)
QtCore.QObject.connect(values,QtCore.SIGNAL("valueChanged(double)"),self.setSill)
# check for Parts library and Arch presets
# because of the use of FreeCADGui.doCommand() backslashes in the
# paths in librarypresets need to be double escaped "\\\\", so let's
# use forward slashes instead...
self.librarypresets = []
librarypath = FreeCAD.ParamGet("User parameter:Plugins/parts_library").GetString("destination", "")
# librarypath should have only forward slashes already, but let's use replace() anyway just to be sure:
librarypath = librarypath.replace("\\", "/") + "/Architectural Parts"
presetdir = FreeCAD.getUserAppDataDir().replace("\\", "/") + "/Arch"
for path in [librarypath, presetdir]:
if os.path.isdir(path):
for wtype in ["Windows", "Doors"]:
wdir = path + "/" + wtype
if os.path.isdir(wdir):
for subtype in os.listdir(wdir):
subdir = wdir + "/" + subtype
if os.path.isdir(subdir):
for subfile in os.listdir(subdir):
if (os.path.isfile(subdir + "/" + subfile)
and subfile.lower().endswith(".fcstd")):
self.librarypresets.append([wtype + " - " + subtype + " - " + subfile[:-6],
subdir + "/" + subfile])
# presets box
labelp = QtGui.QLabel(translate("Arch","Preset"))
valuep = QtGui.QComboBox()
valuep.setMinimumContentsLength(6)
valuep.setSizeAdjustPolicy(QtGui.QComboBox.AdjustToContents)
valuep.addItems(WindowPresets)
valuep.setCurrentIndex(self.Preset)
grid.addWidget(labelp,2,0,1,1)
grid.addWidget(valuep,2,1,1,1)
QtCore.QObject.connect(valuep,QtCore.SIGNAL("currentIndexChanged(int)"),self.setPreset)
for it in self.librarypresets:
valuep.addItem(it[0])
# image display
self.pic = QtGui.QLabel()
grid.addWidget(self.pic,3,0,1,2)
self.pic.setFixedHeight(128)
self.pic.hide()
# SVG display
self.im = QtSvg.QSvgWidget(":/ui/ParametersWindowFixed.svg")
self.im.setMaximumWidth(200)
self.im.setMinimumHeight(120)
grid.addWidget(self.im,4,0,1,2)
#self.im.hide()
# parameters
i = 5
for param in self.wparams:
lab = QtGui.QLabel(translate("Arch",param))
setattr(self,"val"+param,ui.createWidget("Gui::InputField"))
wid = getattr(self,"val"+param)
if param == "Width":
wid.setText(FreeCAD.Units.Quantity(self.Width,FreeCAD.Units.Length).UserString)
elif param == "Height":
wid.setText(FreeCAD.Units.Quantity(self.Height,FreeCAD.Units.Length).UserString)
elif param == "O1":
n = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Arch").GetFloat("WindowO1",0.0)
wid.setText(FreeCAD.Units.Quantity(n,FreeCAD.Units.Length).UserString)
setattr(self,param,n)
elif param == "W1":
n = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Arch").GetFloat("WindowW1",self.Thickness*2)
wid.setText(FreeCAD.Units.Quantity(n,FreeCAD.Units.Length).UserString)
setattr(self,param,n)
else:
n = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Arch").GetFloat("Window"+param,self.Thickness)
wid.setText(FreeCAD.Units.Quantity(n,FreeCAD.Units.Length).UserString)
setattr(self,param,n)
grid.addWidget(lab,i,0,1,1)
grid.addWidget(wid,i,1,1,1)
i += 1
valueChanged = self.getValueChanged(param)
FreeCAD.wid = wid
QtCore.QObject.connect(getattr(self,"val"+param),QtCore.SIGNAL("valueChanged(double)"), valueChanged)
# restore saved states
if self.doormode:
i = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Arch").GetInt("DoorPreset",0)
d = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Arch").GetFloat("DoorSill",0)
else:
i = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Arch").GetInt("WindowPreset",0)
d = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Arch").GetFloat("WindowSill",0)
if i < valuep.count():
valuep.setCurrentIndex(i)
values.setText(FreeCAD.Units.Quantity(d,FreeCAD.Units.Length).UserString)
return w

View File

@@ -0,0 +1,352 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>formGate</class>
<widget class="QWidget" name="formGate">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>317</width>
<height>289</height>
</rect>
</property>
<property name="windowTitle">
<string>Puerta:</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="leftMargin">
<number>5</number>
</property>
<property name="topMargin">
<number>5</number>
</property>
<property name="rightMargin">
<number>5</number>
</property>
<property name="bottomMargin">
<number>5</number>
</property>
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Puerta</string>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Tipo de puerta</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QDoubleSpinBox" name="editGateHeight">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>140</width>
<height>0</height>
</size>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buttonSymbols">
<enum>QAbstractSpinBox::NoButtons</enum>
</property>
<property name="maximum">
<double>5.000000000000000</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
<property name="value">
<double>2.000000000000000</double>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="labelVerticalGap">
<property name="text">
<string>Ancho (m)</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QDoubleSpinBox" name="editGateWidth">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>140</width>
<height>0</height>
</size>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buttonSymbols">
<enum>QAbstractSpinBox::NoButtons</enum>
</property>
<property name="maximum">
<double>10000.000000000000000</double>
</property>
<property name="singleStep">
<double>0.500000000000000</double>
</property>
<property name="value">
<double>0.850000000000000</double>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Alto (m)</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="comboFrameType">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>140</width>
<height>0</height>
</size>
</property>
<item>
<property name="text">
<string>Simple</string>
</property>
</item>
<item>
<property name="text">
<string>Doble</string>
</property>
</item>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="title">
<string>Poste</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<property name="leftMargin">
<number>9</number>
</property>
<property name="topMargin">
<number>9</number>
</property>
<property name="rightMargin">
<number>9</number>
</property>
<property name="bottomMargin">
<number>9</number>
</property>
<property name="spacing">
<number>6</number>
</property>
<item row="3" column="2">
<widget class="QDoubleSpinBox" name="editPostBuried">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>140</width>
<height>0</height>
</size>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buttonSymbols">
<enum>QAbstractSpinBox::NoButtons</enum>
</property>
<property name="maximum">
<double>2000.000000000000000</double>
</property>
<property name="singleStep">
<double>50.000000000000000</double>
</property>
<property name="value">
<double>700.000000000000000</double>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_10">
<property name="text">
<string>Alto (m)</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_17">
<property name="text">
<string>Enterramiento (m)</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QDoubleSpinBox" name="editPostHeight">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>140</width>
<height>0</height>
</size>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buttonSymbols">
<enum>QAbstractSpinBox::NoButtons</enum>
</property>
<property name="decimals">
<number>3</number>
</property>
<property name="maximum">
<double>5000.000000000000000</double>
</property>
<property name="singleStep">
<double>500.000000000000000</double>
</property>
<property name="value">
<double>2000.000000000000000</double>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_9">
<property name="text">
<string>Ancho (mm)</string>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QSpinBox" name="editPostWidth">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>140</width>
<height>0</height>
</size>
</property>
<property name="layoutDirection">
<enum>Qt::LeftToRight</enum>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buttonSymbols">
<enum>QAbstractSpinBox::NoButtons</enum>
</property>
<property name="maximum">
<number>200</number>
</property>
<property name="value">
<number>80</number>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QWidget" name="widget" native="true">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Espacio (mm)</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="editGap">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>140</width>
<height>0</height>
</size>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buttonSymbols">
<enum>QAbstractSpinBox::NoButtons</enum>
</property>
<property name="maximum">
<number>10</number>
</property>
<property name="value">
<number>2</number>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@@ -0,0 +1,232 @@
import FreeCAD
import Part
import ArchComponent
if FreeCAD.GuiUp:
import FreeCADGui
from PySide import QtCore
from PySide.QtCore import QT_TRANSLATE_NOOP
else:
# \cond
def translate(ctxt, txt):
return txt
def QT_TRANSLATE_NOOP(ctxt, txt):
return txt
# \endcond
try:
_fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
def _fromUtf8(s):
return s
def makeFencePost(diameter=48, length=3000, placement=None, name="FencePost"):
obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", name)
obj.Label = name
FencePost(obj)
if FreeCAD.GuiUp:
ViewProviderFencePost(obj.ViewObject)
obj.Length = length
obj.Diameter = diameter
if placement:
obj.Placement = placement
return obj
def makeFenceReinforcePost(diameter=48, length=3000, placement=None, name="Post"):
obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", name)
obj.Label = name
FenceReinforcePost(obj)
if FreeCAD.GuiUp:
ViewProviderFencePost(obj.ViewObject)
obj.Length = length
obj.Diameter = diameter
if placement:
obj.Placement = placement
return obj
class FencePost(ArchComponent.Component):
def __init__(self, obj):
ArchComponent.Component.__init__(self, obj)
self.setProperties(obj)
obj.IfcType = "Pipe Segment"
self.Type = "FencePost"
def setProperties(self, obj):
pl = obj.PropertiesList
if not "Diameter" in pl:
obj.addProperty("App::PropertyLength", "Diameter", "Pipe",
QT_TRANSLATE_NOOP("App::Property", "The diameter of this pipe, if not based on a profile")
).Diameter = 48
'''if not "Thickness" in pl:
obj.addProperty("App::PropertyLength", "Thickness", "Pipe",
QT_TRANSLATE_NOOP("App::Property", "The Thickness of this pipe, if not based on a profile")
).Thickness = 4'''
if not "Length" in pl:
obj.addProperty("App::PropertyLength", "Length", "Pipe",
QT_TRANSLATE_NOOP("App::Property", "The length of this pipe, if not based on an edge")
).Length = 3000
def onDocumentRestored(self, obj):
ArchComponent.Component.onDocumentRestored(self, obj)
self.setProperties(obj)
def get_axis(self, obj, lip_heigth):
wire = Part.makeLine(FreeCAD.Vector(0, 0, 0), FreeCAD.Vector(0, 0, obj.Length.Value - lip_heigth))
#wire = Part.makePolygon(FreeCAD.Vector(0, 0, obj.Length.Value - lip_heigth),)
return Part.Wire(wire)
def execute(self, obj):
pl = obj.Placement
lip_heigth = 20
radius = obj.Diameter.Value / 2
# para que sea una función que sirva para los postes rectos y con curva:
axis = self.get_axis(obj, lip_heigth)
profile = Part.Wire([Part.Circle(FreeCAD.Vector(0,0,0), FreeCAD.Vector(0,0,1), radius).toShape()])
post = axis.makePipeShell([profile, ],True,True,2)
lip = Part.makeCylinder(radius + 2, lip_heigth)
lip = lip.makeFillet(5, [lip.Edges[0]])
# Obtener caras
face_post = post.Faces[2] # Cara superior del cilindro largo
face_lip = lip.Faces[2] # Cara inferior del cilindro corto
# Calcular centro y normal de las caras
face_post_center = face_post.CenterOfMass
face_post_normal = face_post.normalAt(0, 0)
face_lip_center = face_lip.CenterOfMass
face_lip_normal = face_lip.normalAt(0, 0)
# Calcular rotación para alinear normales (ajustar dirección)
rotacion = FreeCAD.Rotation(face_lip_normal, -face_post_normal) # Invertir normal del cilindro corto
lip.Placement.Rotation = rotacion.multiply(lip.Placement.Rotation)
# Calcular traslación: mover centro del cilindro corto al centro del cilindro largo
traslacion = face_post_center - rotacion.multVec(face_lip_center)
lip.Placement.Base = traslacion #face_post_center
obj.Shape = post.fuse(lip)
obj.Placement = pl
return
class FenceReinforcePost(ArchComponent.Component):
def __init__(self, obj):
ArchComponent.Component.__init__(self, obj)
self.setProperties(obj)
obj.IfcType = "Pipe Segment"
self.Type = "FencePost"
def setProperties(self, obj):
pl = obj.PropertiesList
if not "Diameter" in pl:
obj.addProperty("App::PropertyLength", "Diameter", "Pipe",
QT_TRANSLATE_NOOP("App::Property", "The diameter of this pipe, if not based on a profile")
).Diameter = 48
if not "Length" in pl:
obj.addProperty("App::PropertyLength", "Length", "Pipe",
QT_TRANSLATE_NOOP("App::Property", "The length of this pipe, if not based on an edge")
).Length = 3000
self.Type = "Pipe"
def onDocumentRestored(self, obj):
ArchComponent.Component.onDocumentRestored(self, obj)
self.setProperties(obj)
def execute(self, obj):
pl = obj.Placement
lip_heigth = 20
post = Part.makeCylinder(obj.Diameter.Value / 2, obj.Length.Value - lip_heigth)
lip = Part.makeCylinder(obj.Diameter.Value / 2 + 2, lip_heigth)
lip = lip.makeFillet(5, [lip.Edges[0]])
lip.translate(FreeCAD.Vector(0, 0, obj.Length.Value - lip_heigth))
obj.Shape = post.fuse(lip)
obj.Placement = pl
return
w = self.getWire(obj)
try:
# sh = w.makePipeShell([p], True, False, 2)
sh = w.revolve(FreeCAD.Vector(0.0, 0.0, 0.0), FreeCAD.Vector(0.0, 0.0, 1.0), 360)
except:
FreeCAD.Console.PrintError(translate("Arch", "Unable to build the pipe") + "\n")
else:
obj.Shape = sh
obj.Placement = pl
def getWire(self, obj):
import Part
sin45 = 0.707106781
radio = obj.Diameter.Value / 2
taph = 20
tapw = radio + 2
chamfer = 5
chamfer2 = chamfer * sin45
edge1 = Part.makeLine(FreeCAD.Vector(0, 0, 0), FreeCAD.Vector(radio, 0, 0))
edge2 = Part.makeLine(FreeCAD.Vector(radio, 0, 0), FreeCAD.Vector(radio, 0, obj.Length.Value - taph))
edge3 = Part.makeLine(FreeCAD.Vector(radio, 0, obj.Length.Value - taph),
FreeCAD.Vector(tapw, 0, obj.Length.Value - taph))
edge4 = Part.makeLine(FreeCAD.Vector(tapw, 0, obj.Length.Value - taph),
FreeCAD.Vector(tapw, 0, obj.Length.Value - chamfer))
if True:
edge5 = Part.makeLine(FreeCAD.Vector(tapw, 0, obj.Length.Value - chamfer),
FreeCAD.Vector(tapw - chamfer, 0, obj.Length.Value))
else:
edge5 = Part.Arc(FreeCAD.Vector(tapw, 0, obj.Length.Value - chamfer),
FreeCAD.Vector(tapw - chamfer2, 0, obj.Length.Value - chamfer2),
FreeCAD.Vector(tapw - chamfer, 0, obj.Length.Value)
).toShape()
edge6 = Part.makeLine(FreeCAD.Vector(tapw - chamfer, 0, obj.Length.Value),
FreeCAD.Vector(0, 0, obj.Length.Value))
w = Part.Wire([edge1, edge2, edge3, edge4, edge5, edge6])
return w
class ViewProviderFencePost(ArchComponent.ViewProviderComponent):
"A View Provider for the Pipe object"
def __init__(self, vobj):
ArchComponent.ViewProviderComponent.__init__(self, vobj)
def getIcon(self):
return ":/icons/Arch_Pipe_Tree.svg"
class CommandFencePost:
"the Arch Pipe command definition"
def GetResources(self):
return {'Pixmap': 'Arch_Pipe',
'MenuText': QT_TRANSLATE_NOOP("Arch_Pipe", "Pipe"),
'Accel': "P, I",
'ToolTip': QT_TRANSLATE_NOOP("Arch_Pipe", "Creates a pipe object from a given Wire or Line")}
def IsActive(self):
return not FreeCAD.ActiveDocument is None
def Activated(self):
makeFencePost()
FreeCAD.ActiveDocument.recompute()