Merge branch 'master' into feature/tooltable

This commit is contained in:
Daniel Wood
2019-08-26 21:30:16 +01:00
committed by GitHub
15 changed files with 254 additions and 162 deletions

1
.gitignore vendored
View File

@@ -20,6 +20,7 @@ ui_*.h
moc_*.cpp
Makefile
CMakeCache.txt
CMakeLists.txt.user
config.h
install_manifest.txt
/bin/

View File

@@ -31,6 +31,7 @@
#include <qglobal.h>
#include <Base/FileInfo.h>
#include <Base/Console.h>
#include "SoFCVectorizeSVGAction.h"
using namespace Gui;
@@ -306,7 +307,7 @@ void SoFCVectorizeSVGActionP::printTriangle(const SbVec3f * v, const SbColor * c
<< "; stroke:#"
<< std::hex << std::setw(6) << std::setfill('0') << (cc >> 8)
<< ";" << std::endl
<< " stroke-width:1.0;" << std::endl
<< " stroke-width:" << publ->getLineWidth() << ";" << std::endl
<< " stroke-linecap:round;stroke-linejoin:round\"/>" << std::endl;
}
@@ -350,8 +351,9 @@ void SoFCVectorizeSVGActionP::printLine(const SoVectorizeLine * item) const
<< "x1=\"" << v[0][0] << "\" y1=\"" << v[0][1] << "\" "
<< "x2=\"" << v[1][0] << "\" y2=\"" << v[1][1] << "\" "
<< "stroke=\"#"
<< std::hex << std::setw(6) << std::setfill('0') << (cc >> 8)
<< "\" stroke-width=\"1px\" />\n";
<< std::hex << std::setw(6) << std::setfill('0') << (cc >> 8) << "\""
<< " stroke-linecap=\"square\" "
<< " stroke-width=\"" << publ->getLineWidth() << "\" />\n";
}
void SoFCVectorizeSVGActionP::printPoint(const SoVectorizePoint * item) const
@@ -375,7 +377,10 @@ void SoFCVectorizeSVGAction::initClass(void)
SO_ACTION_INIT_CLASS(SoFCVectorizeSVGAction, SoVectorizeAction);
}
SoFCVectorizeSVGAction::SoFCVectorizeSVGAction()
SoFCVectorizeSVGAction::SoFCVectorizeSVGAction() :
m_backgroundState(true),
m_lineWidth(1.0),
m_usemm(false)
{
SO_ACTION_CONSTRUCTOR(SoFCVectorizeSVGAction);
this->setOutput(new SoSVGVectorOutput);
@@ -400,12 +405,18 @@ void SoFCVectorizeSVGAction::printHeader(void) const
str << "<!-- Created with FreeCAD (http://www.freecadweb.org) -->" << std::endl;
str << "<svg xmlns=\"http://www.w3.org/2000/svg\"" << std::endl;
str << " xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:ev=\"http://www.w3.org/2001/xml-events\"" << std::endl;
str << " version=\"1.1\" baseProfile=\"full\"" << std::endl;
str << " version=\"1.1\" baseProfile=\"full\"" << std::endl;
SbVec2f size = getPageSize();
if (this->getOrientation() == LANDSCAPE)
if (this->getOrientation() == LANDSCAPE) {
SbSwap<float>(size[0], size[1]);
str << " width=\"" << size[0] << "\" height=\"" << size[1] << "\">" << std::endl;
}
if (getUseMM()) {
str << " width=\"" << size[0] << "mm\" height=\"" << size[1] << "mm\""<< std::endl;
str << " viewBox=\"0 0 " << size[0] << " " << size[1] << "\">" << std::endl;
} else { //original code used px
str << " width=\"" << size[0] << "\" height=\"" << size[1] << "\">" << std::endl;
}
str << "<g>" << std::endl;
}
@@ -447,7 +458,7 @@ void SoFCVectorizeSVGAction::printBackground(void) const
str << " style=\"fill:#"
<< std::hex << std::setw(6) << std::setfill('0') << (cc >> 8)
<< ";fill-opacity:1;fill-rule:evenodd;stroke:none;"
"stroke-width:1px;stroke-linecap:butt;stroke-linejoin:"
"stroke-width:" << getLineWidth() << ";stroke-linecap:butt;stroke-linejoin:"
"miter;stroke-opacity:1\" />\n";
str << "<g>" << std::endl;
}

View File

@@ -62,6 +62,13 @@ public:
static void initClass(void);
SoSVGVectorOutput * getSVGOutput(void) const;
virtual void setBackgroundState(bool b) { m_backgroundState = b; }
virtual bool getBackgroundState(void) const { return m_backgroundState; }
virtual void setLineWidth(double w) { m_lineWidth = w; }
virtual double getLineWidth(void) const { return m_lineWidth; }
virtual void setUseMM(bool b) { m_usemm = b; }
virtual bool getUseMM(void) const { return m_usemm; }
protected:
virtual void printHeader(void) const;
virtual void printFooter(void) const;
@@ -72,6 +79,9 @@ protected:
private:
SoFCVectorizeSVGActionP* p;
friend class SoFCVectorizeSVGActionP;
bool m_backgroundState;
double m_lineWidth;
bool m_usemm;
};
} // namespace Gui

View File

@@ -30,8 +30,9 @@ class IfcRoot:
if prop == "IfcType":
self.setupIfcAttributes(obj)
self.setupIfcComplexAttributes(obj)
if obj.getGroupOfProperty(prop) == "IFC Attributes":
self.setObjIfcAttributeValue(obj, prop, obj.getPropertyByName(prop))
if prop in obj.PropertiesList:
if obj.getGroupOfProperty(prop) == "IFC Attributes":
self.setObjIfcAttributeValue(obj, prop, obj.getPropertyByName(prop))
def setupIfcAttributes(self, obj):
ifcTypeSchema = self.getIfcTypeSchema(obj.IfcType)

View File

@@ -947,12 +947,12 @@ class _ViewProviderStructure(ArchComponent.ViewProviderComponent):
p.append([n.x,n.y,n.z])
self.coords.point.setValues(0,len(p),p)
self.pointset.numPoints.setValue(len(p))
self.lineset.coordIndex.setValues(0,len(p)+1,range(len(p))+[-1])
self.lineset.coordIndex.setValues(0,len(p)+1,list(range(len(p)))+[-1])
if hasattr(obj.ViewObject,"NodeType"):
if (obj.ViewObject.NodeType == "Area") and (len(p) > 2):
self.coords.point.set1Value(len(p),p[0][0],p[0][1],p[0][2])
self.lineset.coordIndex.setValues(0,len(p)+2,range(len(p)+1)+[-1])
self.faceset.coordIndex.setValues(0,len(p)+1,range(len(p))+[-1])
self.lineset.coordIndex.setValues(0,len(p)+2,list(range(len(p)+1))+[-1])
self.faceset.coordIndex.setValues(0,len(p)+1,list(range(len(p)))+[-1])
elif prop in ["IfcType"]:
if hasattr(obj.ViewObject,"NodeType"):

View File

@@ -52,8 +52,6 @@ from importIFCHelper import decode
#
# This module provides tools to export IFC files.
DEBUG = False # Set to True to see debug messages. Otherwise, totally silent
if open.__module__ in ['__builtin__','io']:
pyopen = open
# pyopen is use in exporter to open a file in Arch
@@ -116,54 +114,38 @@ def getPreferences():
"""retrieves IFC preferences"""
global DEBUG, PREFIX_NUMBERS, SKIP, SEPARATE_OPENINGS
global ROOT_ELEMENT, GET_EXTRUSIONS, MERGE_MATERIALS
global MERGE_MODE_ARCH, MERGE_MODE_STRUCT, CREATE_CLONES
global FORCE_BREP, IMPORT_PROPERTIES, STORE_UID, SERIALIZE
global SPLIT_LAYERS, EXPORT_2D, FULL_PARAMETRIC, FITVIEW_ONIMPORT
global ADD_DEFAULT_SITE, ADD_DEFAULT_STOREY, ADD_DEFAULT_BUILDING
p = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Arch")
if FreeCAD.GuiUp and p.GetBool("ifcShowDialog",False):
import FreeCADGui
FreeCADGui.showPreferences("Import-Export",0)
DEBUG = p.GetBool("ifcDebug",False)
PREFIX_NUMBERS = p.GetBool("ifcPrefixNumbers",False)
SKIP = p.GetString("ifcSkip","").split(",")
SEPARATE_OPENINGS = p.GetBool("ifcSeparateOpenings",False)
ROOT_ELEMENT = p.GetString("ifcRootElement","IfcProduct")
GET_EXTRUSIONS = p.GetBool("ifcGetExtrusions",False)
MERGE_MATERIALS = p.GetBool("ifcMergeMaterials",False)
MERGE_MODE_ARCH = p.GetInt("ifcImportModeArch",0)
MERGE_MODE_STRUCT = p.GetInt("ifcImportModeStruct",1)
if MERGE_MODE_ARCH > 0:
SEPARATE_OPENINGS = False
GET_EXTRUSIONS = False
if not SEPARATE_OPENINGS:
SKIP.append("IfcOpeningElement")
CREATE_CLONES = p.GetBool("ifcCreateClones",True)
FORCE_BREP = p.GetBool("ifcExportAsBrep",False)
IMPORT_PROPERTIES = p.GetBool("ifcImportProperties",False)
STORE_UID = p.GetBool("ifcStoreUid",True)
SERIALIZE = p.GetBool("ifcSerialize",False)
SPLIT_LAYERS = p.GetBool("ifcSplitLayers",False)
EXPORT_2D = p.GetBool("ifcExport2D",True)
FULL_PARAMETRIC = p.GetBool("IfcExportFreeCADProperties",False)
FITVIEW_ONIMPORT = p.GetBool("ifcFitViewOnImport",False)
ADD_DEFAULT_SITE = p.GetBool("IfcAddDefaultSite",False)
ADD_DEFAULT_STOREY = p.GetBool("IfcAddDefaultStorey",False)
ADD_DEFAULT_BUILDING = p.GetBool("IfcAddDefaultBuilding",True)
preferences = {
'DEBUG': p.GetBool("ifcDebug",False),
'CREATE_CLONES': p.GetBool("ifcCreateClones",True),
'FORCE_BREP': p.GetBool("ifcExportAsBrep",False),
'STORE_UID': p.GetBool("ifcStoreUid",True),
'SERIALIZE': p.GetBool("ifcSerialize",False),
'EXPORT_2D': p.GetBool("ifcExport2D",True),
'FULL_PARAMETRIC': p.GetBool("IfcExportFreeCADProperties",False),
'ADD_DEFAULT_SITE': p.GetBool("IfcAddDefaultSite",False),
'ADD_DEFAULT_STOREY': p.GetBool("IfcAddDefaultStorey",False),
'ADD_DEFAULT_BUILDING': p.GetBool("IfcAddDefaultBuilding",True)
}
return preferences
# ************************************************************************************************
# ********** export IFC ****************
def export(exportList,filename,colors=None):
def export(exportList,filename,colors=None,preferences=None):
"""export(exportList,filename,colors=None) -- exports FreeCAD contents to an IFC file.
"""export(exportList,filename,colors=None,preferences=None) -- exports FreeCAD contents to an IFC file.
colors is an optional dictionary of objName:shapeColorTuple or objName:diffuseColorList elements
to be used in non-GUI mode if you want to be able to export colors."""
getPreferences()
if preferences is None:
preferences = getPreferences()
try:
global ifcopenshell
@@ -189,7 +171,7 @@ def export(exportList,filename,colors=None):
schema = ["IFC4", "IFC2X3"][FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Arch").GetInt("IfcVersion",0)]
else:
schema = "IFC2X3"
if DEBUG: print("Exporting an",schema,"file...")
if preferences['DEBUG']: print("Exporting an",schema,"file...")
template = template.replace("$ifcschema",schema)
template = template.replace("$owner",owner)
template = template.replace("$company",FreeCAD.ActiveDocument.Company)
@@ -224,7 +206,7 @@ def export(exportList,filename,colors=None):
objectslist = [obj for obj in objectslist if obj not in annotations]
objectslist = Arch.pruneIncluded(objectslist,strict=True)
objectslist = [obj for obj in objectslist if Draft.getType(obj) not in ["Dimension","Material","MaterialContainer","WorkingPlaneProxy"]]
if FULL_PARAMETRIC:
if preferences['FULL_PARAMETRIC']:
objectslist = Arch.getAllChildren(objectslist)
contextCreator = exportIFCHelper.ContextCreator(ifcfile, objectslist)
@@ -254,7 +236,7 @@ def export(exportList,filename,colors=None):
# build clones table
if CREATE_CLONES:
if preferences['CREATE_CLONES']:
for o in objectslist:
b = Draft.getCloneBase(o,strict=True)
if b:
@@ -292,7 +274,7 @@ def export(exportList,filename,colors=None):
if not uid:
uid = ifcopenshell.guid.new()
# storing the uid for further use
if STORE_UID and hasattr(obj,"IfcData"):
if preferences['STORE_UID'] and hasattr(obj,"IfcData"):
d = obj.IfcData
d["IfcUID"] = uid
obj.IfcData = d
@@ -347,7 +329,7 @@ def export(exportList,filename,colors=None):
if len(ifcaxes) > 2:
w = ifcaxes[2]
if u and v:
if DEBUG: print(str(count).ljust(3)," : ", ifctype, " (",str(len(ifcpols)),"axes ) : ",name)
if preferences['DEBUG']: print(str(count).ljust(3)," : ", ifctype, " (",str(len(ifcpols)),"axes ) : ",name)
xvc = ifcbin.createIfcDirection((1.0,0.0,0.0))
zvc = ifcbin.createIfcDirection((0.0,0.0,1.0))
ovc = ifcbin.createIfcCartesianPoint((0.0,0.0,0.0))
@@ -375,12 +357,12 @@ def export(exportList,filename,colors=None):
# getting the representation
representation,placement,shapetype = getRepresentation(ifcfile,context,obj,forcebrep=(brepflag or FORCE_BREP),colors=colors)
representation,placement,shapetype = getRepresentation(ifcfile,context,obj,forcebrep=(brepflag or preferences['FORCE_BREP']),colors=colors,preferences=preferences)
if getstd:
if isStandardCase(obj,ifctype):
ifctype += "StandardCase"
if DEBUG: print(str(count).ljust(3)," : ", ifctype, " (",shapetype,") : ",name)
if preferences['DEBUG']: print(str(count).ljust(3)," : ", ifctype, " (",shapetype,") : ",name)
# setting the arguments
@@ -417,8 +399,8 @@ def export(exportList,filename,colors=None):
if hasattr(obj,"Additions") and (shapetype in ["extrusion","no shape"]):
for o in obj.Additions:
r2,p2,c2 = getRepresentation(ifcfile,context,o,colors=colors)
if DEBUG: print(" adding ",c2," : ",o.Label)
r2,p2,c2 = getRepresentation(ifcfile,context,o,colors=colors,preferences=preferences)
if preferences['DEBUG']: print(" adding ",c2," : ",o.Label)
l = o.Label
if six.PY2:
l = l.encode("utf8")
@@ -454,8 +436,8 @@ def export(exportList,filename,colors=None):
guests.append(o)
if hasattr(obj,"Subtractions") and (shapetype in ["extrusion","no shape"]):
for o in obj.Subtractions + guests:
r2,p2,c2 = getRepresentation(ifcfile,context,o,subtraction=True,colors=colors)
if DEBUG: print(" subtracting ",c2," : ",o.Label)
r2,p2,c2 = getRepresentation(ifcfile,context,o,subtraction=True,colors=colors,preferences=preferences)
if preferences['DEBUG']: print(" subtracting ",c2," : ",o.Label)
l = o.Label
if six.PY2:
l = l.encode("utf8")
@@ -494,7 +476,7 @@ def export(exportList,filename,colors=None):
psets = {}
for key,value in obj.IfcProperties.items():
pset, pname, ptype, pvalue = getPropertyData(key,value)
pset, pname, ptype, pvalue = getPropertyData(key,value,preferences)
p = ifcbin.createIfcPropertySingleValue(str(pname),str(ptype),pvalue)
psets.setdefault(pset,[]).append(p)
for pname,props in psets.items():
@@ -565,7 +547,7 @@ def export(exportList,filename,colors=None):
for cat in propertiesDic:
props = []
for prop in propertiesDic[cat]:
if DEBUG:
if preferences['DEBUG']:
print("key",prop["key"],type(prop["key"]))
print("tp",prop["tp"],type(prop["tp"]))
print("val",prop["val"],type(prop["val"]))
@@ -593,7 +575,7 @@ def export(exportList,filename,colors=None):
if obj.IfcData:
ifcprop = True
#if DEBUG : print(" adding ifc attributes")
#if preferences['DEBUG'] : print(" adding ifc attributes")
props = []
for key in obj.IfcData:
if not (key in ["attributes", "complex_attributes", "IfcUID", "FlagForceBrep"]):
@@ -609,7 +591,7 @@ def export(exportList,filename,colors=None):
val = "(".join(r[1:])
val = val.strip("'")
val = val.strip('"')
#if DEBUG: print(" property ",key," : ",val.encode("utf8"), " (", str(tp), ")")
#if preferences['DEBUG']: print(" property ",key," : ",val.encode("utf8"), " (", str(tp), ")")
if tp in ["IfcLabel","IfcText","IfcIdentifier",'IfcDescriptiveMeasure']:
if six.PY2:
val = val.encode("utf8")
@@ -641,7 +623,7 @@ def export(exportList,filename,colors=None):
)
if not ifcprop:
#if DEBUG : print("no ifc properties to export")
#if preferences['DEBUG'] : print("no ifc properties to export")
pass
# Quantities
@@ -676,7 +658,7 @@ def export(exportList,filename,colors=None):
[product],eltq
)
if FULL_PARAMETRIC:
if preferences['FULL_PARAMETRIC']:
# exporting all the object properties
@@ -737,7 +719,7 @@ def export(exportList,filename,colors=None):
itype = "IfcText"
ivalue = "FreeCADLink_" + t.Name
else:
if DEBUG: print("Unable to encode property ",prop," of type ",ptype)
if preferences['DEBUG']: print("Unable to encode property ",prop," of type ",ptype)
if itype:
# TODO add description
if realm == "Gui":
@@ -870,7 +852,7 @@ def export(exportList,filename,colors=None):
childfloors
)
buildings.append(b)
if not defaulthost and not ADD_DEFAULT_STOREY:
if not defaulthost and not preferences['ADD_DEFAULT_STOREY']:
defaulthost = b
# sites
@@ -892,8 +874,8 @@ def export(exportList,filename,colors=None):
# add default site, building and storey as required
if not sites:
if ADD_DEFAULT_SITE:
if DEBUG: print("No site found. Adding default site")
if preferences['ADD_DEFAULT_SITE']:
if preferences['DEBUG']: print("No site found. Adding default site")
sites = [ifcfile.createIfcSite(
ifcopenshell.guid.new(),
history,"Default Site",
@@ -918,8 +900,8 @@ def export(exportList,filename,colors=None):
project,sites
)
if not buildings:
if ADD_DEFAULT_BUILDING:
if DEBUG: print("No building found. Adding default building")
if preferences['ADD_DEFAULT_BUILDING']:
if preferences['DEBUG']: print("No building found. Adding default building")
buildings = [ifcfile.createIfcBuilding(
ifcopenshell.guid.new(),
history,
@@ -973,7 +955,7 @@ def export(exportList,filename,colors=None):
untreated.append(v)
if untreated:
if not defaulthost:
if ADD_DEFAULT_STOREY:
if preferences['ADD_DEFAULT_STOREY']:
defaulthost = ifcfile.createIfcBuildingStorey(
ifcopenshell.guid.new(),
history,
@@ -986,9 +968,10 @@ def export(exportList,filename,colors=None):
"ELEMENT",
None
)
# if ADD_DEFAULT_STOREY is on, we need a building to host it, regardless of ADD_DEFAULT_BUILDING
# if preferences['ADD_DEFAULT_STOREY'] is on, we need a building
# to host it, regardless of preferences['ADD_DEFAULT_BUILDING']
if not buildings:
if DEBUG: print("No building found. Adding default building")
if preferences['DEBUG']: print("No building found. Adding default building")
buildings = [ifcfile.createIfcBuilding(
ifcopenshell.guid.new(),
history,
@@ -1041,7 +1024,7 @@ def export(exportList,filename,colors=None):
)
else:
# no default host: aggregate unassigned objects directly under the IfcProject - WARNING: NON STANDARD
if DEBUG: print("WARNING - Default building generation is disabled. You are producing a non-standard file.")
if preferences['DEBUG']: print("WARNING - Default building generation is disabled. You are producing a non-standard file.")
ifcfile.createIfcRelAggregates(
ifcopenshell.guid.new(),
history,
@@ -1098,9 +1081,9 @@ def export(exportList,filename,colors=None):
# 2D objects
annos = {}
if EXPORT_2D:
if preferences['EXPORT_2D']:
curvestyles = {}
if annotations and DEBUG: print("exporting 2D objects...")
if annotations and preferences['DEBUG']: print("exporting 2D objects...")
for anno in annotations:
xvc = ifcbin.createIfcDirection((1.0,0.0,0.0))
zvc = ifcbin.createIfcDirection((0.0,0.0,1.0))
@@ -1253,7 +1236,7 @@ def export(exportList,filename,colors=None):
remaining = [anno for anno in annos.values() if anno not in swallowed]
if remaining:
if not defaulthost:
if ADD_DEFAULT_STOREY:
if preferences['ADD_DEFAULT_STOREY']:
defaulthost = ifcfile.createIfcBuildingStorey(
ifcopenshell.guid.new(),
history,
@@ -1266,7 +1249,9 @@ def export(exportList,filename,colors=None):
"ELEMENT",
None
)
# if ADD_DEFAULT_STOREY is on, we need a building to host it, regardless of ADD_DEFAULT_BUILDING
# if preferences['ADD_DEFAULT_STOREY'] is on, we need a
# building to host it, regardless of
# preferences['ADD_DEFAULT_BUILDING']
if not buildings:
buildings = [ifcfile.createIfcBuilding(
ifcopenshell.guid.new(),
@@ -1307,7 +1292,7 @@ def export(exportList,filename,colors=None):
buildings[0],
[defaulthost]
)
elif ADD_DEFAULT_BUILDING:
elif preferences['ADD_DEFAULT_BUILDING']:
if not buildings:
defaulthost = ifcfile.createIfcBuilding(
ifcopenshell.guid.new(),
@@ -1360,19 +1345,19 @@ def export(exportList,filename,colors=None):
remaining
)
if DEBUG: print("writing ",filename,"...")
if preferences['DEBUG']: print("writing ",filename,"...")
filename = decode(filename)
ifcfile.write(filename)
if STORE_UID:
if preferences['STORE_UID']:
# some properties might have been changed
FreeCAD.ActiveDocument.recompute()
os.remove(templatefile)
if DEBUG and ifcbin.compress:
if preferences['DEBUG'] and ifcbin.compress:
f = pyopen(filename,"r")
s = len(f.read().split("\n"))
f.close()
@@ -1383,7 +1368,7 @@ def export(exportList,filename,colors=None):
# ************************************************************************************************
# ********** helper for export IFC **************
def getPropertyData(key,value):
def getPropertyData(key,value,preferences):
# in 0.18, properties in IfcProperties dict are stored as "key":"pset;;type;;value" or "key":"type;;value"
# in 0.19, key = name;;pset, value = ptype;;value (because there can be several props with same name)
@@ -1404,10 +1389,10 @@ def getPropertyData(key,value):
ptype = value[0]
pvalue = value[1]
else:
if DEBUG:print(" unable to export property:",pname,value)
if preferences['DEBUG']:print(" unable to export property:",pname,value)
return pset, pname, ptype, None
#if DEBUG: print(" property ",pname," : ",pvalue.encode("utf8"), " (", str(ptype), ") in ",pset)
#if preferences['DEBUG']: print(" property ",pname," : ",pvalue.encode("utf8"), " (", str(ptype), ") in ",pset)
if ptype in ["IfcLabel","IfcText","IfcIdentifier",'IfcDescriptiveMeasure']:
if six.PY2:
pvalue = pvalue.encode("utf8")
@@ -1432,7 +1417,7 @@ def getPropertyData(key,value):
except:
if six.PY2:
pvalue = pvalue.encode("utf8")
if DEBUG:print(" warning: unable to export property as numeric value:",pname,pvalue)
if preferences['DEBUG']:print(" warning: unable to export property as numeric value:",pname,pvalue)
# print('pset: {}, pname: {}, ptype: {}, pvalue: {}'.format(pset, pname, ptype, pvalue))
return pset, pname, ptype, pvalue
@@ -1700,7 +1685,7 @@ def getProfile(ifcfile,p):
return profile
def getRepresentation(ifcfile,context,obj,forcebrep=False,subtraction=False,tessellation=1,colors=None):
def getRepresentation(ifcfile,context,obj,forcebrep=False,subtraction=False,tessellation=1,colors=None,preferences=None):
"""returns an IfcShapeRepresentation object or None"""
@@ -1857,7 +1842,7 @@ def getRepresentation(ifcfile,context,obj,forcebrep=False,subtraction=False,tess
from ifcopenshell import geom
serialized = False
if hasattr(geom,"serialise") and obj.isDerivedFrom("Part::Feature") and SERIALIZE:
if hasattr(geom,"serialise") and obj.isDerivedFrom("Part::Feature") and preferences['SERIALIZE']:
if obj.Shape.Faces:
sh = obj.Shape.copy()
sh.Placement = obj.getGlobalPlacement()
@@ -1890,7 +1875,7 @@ def getRepresentation(ifcfile,context,obj,forcebrep=False,subtraction=False,tess
dataset = fcshape.Solids
else:
dataset = fcshape.Shells
#if DEBUG: print("Warning! object contains no solids")
#if preferences['DEBUG']: print("Warning! object contains no solids")
for fcsolid in dataset:
fcsolid.scale(0.001) # to meters

View File

@@ -192,7 +192,7 @@ def open(filename,skip=[],only=[],root=None):
def insert(filename,docname,skip=[],only=[],root=None,preferences=None):
"""insert(filename,docname,skip=[],only=[],root=None): imports the contents of an IFC file.
"""insert(filename,docname,skip=[],only=[],root=None,preferences=None): imports the contents of an IFC file.
skip can contain a list of ids of objects to be skipped, only can restrict the import to
certain object ids (will also get their children) and root can be used to
import only the derivates of a certain element type (default = ifcProduct)."""

View File

@@ -1144,6 +1144,7 @@ class DraftToolBar:
self.isCopy.setChecked(p.GetBool("OffsetCopyMode",False))
self.occOffset.show()
self.labelRadius.setText(translate("draft","Distance"))
self.radiusValue.setToolTip(translate("draft", "Offset distance"))
self.radiusValue.setText(FreeCAD.Units.Quantity(0,FreeCAD.Units.Length).UserString)
todo.delay(self.radiusValue.setFocus,None)
self.radiusValue.selectAll()
@@ -1214,6 +1215,7 @@ class DraftToolBar:
self.taskUi(title)
self.radiusUi()
self.labelRadius.setText(translate("draft","Distance"))
self.radiusValue.setToolTip(translate("draft", "Trim distance"))
self.radiusValue.setText(FreeCAD.Units.Quantity(0,FreeCAD.Units.Length).UserString)
todo.delay(self.radiusValue.setFocus,None)
self.radiusValue.selectAll()
@@ -1221,6 +1223,7 @@ class DraftToolBar:
def radiusUi(self):
self.hideXYZ()
self.labelRadius.setText(translate("draft", "Radius"))
self.radiusValue.setToolTip(translate("draft", "Radius of Circle"))
self.labelRadius.show()
self.radiusValue.setText(FreeCAD.Units.Quantity(0,FreeCAD.Units.Length).UserString)
self.radiusValue.show()

View File

@@ -324,9 +324,14 @@ class Snapper:
if (not self.maxEdges) or (len(shape.Edges) <= self.maxEdges):
if "Edge" in comp:
# we are snapping to an edge
en = int(comp[4:])-1
if len(shape.Edges) > en:
edge = shape.Edges[en]
edge = None
if shape.ShapeType == "Edge":
edge = shape
else:
en = int(comp[4:])-1
if len(shape.Edges) > en:
edge = shape.Edges[en]
if edge:
snaps.extend(self.snapToEndpoints(edge))
snaps.extend(self.snapToMidpoint(edge))
snaps.extend(self.snapToPerpendicular(edge,lastpoint))

View File

@@ -1532,14 +1532,16 @@ class Arc(Creator):
if self.closedCircle:
self.drawArc()
else:
self.ui.labelRadius.setText("Start angle")
self.ui.labelRadius.setText(translate("draft","Start angle"))
self.ui.radiusValue.setToolTip(translate("draft","Start angle"))
self.ui.radiusValue.setText(FreeCAD.Units.Quantity(0,FreeCAD.Units.Angle).UserString)
self.linetrack.p1(self.center)
self.linetrack.on()
self.step = 2
FreeCAD.Console.PrintMessage(translate("draft", "Pick start angle")+"\n")
elif (self.step == 2): # choose first angle
self.ui.labelRadius.setText("Aperture")
self.ui.labelRadius.setText(translate("draft","Aperture angle"))
self.ui.radiusValue.setToolTip(translate("draft","Aperture angle"))
self.step = 3
# scale center->point vector for proper display
# u = DraftVecUtils.scaleTo(self.point.sub(self.center), self.rad) obsolete?
@@ -1649,14 +1651,16 @@ class Arc(Creator):
else:
self.step = 2
self.arctrack.setCenter(self.center)
self.ui.labelRadius.setText(translate("draft", "Start Angle"))
self.ui.labelRadius.setText(translate("draft", "Start angle"))
self.ui.radiusValue.setToolTip(translate("draft", "Start angle"))
self.linetrack.p1(self.center)
self.linetrack.on()
self.ui.radiusValue.setText("")
self.ui.radiusValue.setFocus()
FreeCAD.Console.PrintMessage(translate("draft", "Pick start angle")+"\n")
elif (self.step == 2):
self.ui.labelRadius.setText(translate("draft", "Aperture"))
self.ui.labelRadius.setText(translate("draft", "Aperture angle"))
self.ui.radiusValue.setToolTip(translate("draft", "Aperture angle"))
self.firstangle = math.radians(rad)
if DraftVecUtils.equals(plane.axis, Vector(1,0,0)): u = Vector(0,self.rad,0)
else: u = DraftVecUtils.scaleTo(Vector(1,0,0).cross(plane.axis), self.rad)
@@ -2892,6 +2896,7 @@ class Rotate(Modifier):
self.ui.radiusValue.setText(FreeCAD.Units.Quantity(0,FreeCAD.Units.Angle).UserString)
self.ui.hasFill.hide()
self.ui.labelRadius.setText(translate("draft","Base angle"))
self.ui.radiusValue.setToolTip(translate("draft","The base angle you wish to start the rotation from"))
self.arctrack.setCenter(self.center)
for ghost in self.ghosts:
ghost.center(self.center)
@@ -2902,6 +2907,7 @@ class Rotate(Modifier):
def set_start_point(self):
self.ui.labelRadius.setText(translate("draft","Rotation"))
self.ui.radiusValue.setToolTip(translate("draft", "The amount of rotation you wish to perform. The final angle will be the base angle plus this amount."))
self.rad = DraftVecUtils.dist(self.point,self.center)
self.arctrack.on()
self.arctrack.setStartPoint(self.point)
@@ -3029,6 +3035,7 @@ class Rotate(Modifier):
self.ui.radiusUi()
self.ui.hasFill.hide()
self.ui.labelRadius.setText(translate("draft","Base angle"))
self.ui.radiusValue.setToolTip(translate("draft","The base angle you wish to start the rotation from"))
self.step = 1
FreeCAD.Console.PrintMessage(translate("draft", "Pick base angle")+"\n")
@@ -3036,6 +3043,7 @@ class Rotate(Modifier):
"""this function gets called by the toolbar when valid radius have been entered there"""
if (self.step == 1):
self.ui.labelRadius.setText(translate("draft","Rotation"))
self.ui.radiusValue.setToolTip(translate("draft","The amount of rotation you wish to perform. The final angle will be the base angle plus this amount."))
self.firstangle = math.radians(rad)
self.arctrack.setStartAngle(self.firstangle)
self.arctrack.on()
@@ -3904,7 +3912,8 @@ class Trimex(Modifier):
dist = v1.sub(self.newpoint).Length
ghost.p1(self.newpoint)
ghost.p2(v2)
self.ui.labelRadius.setText("Distance")
self.ui.labelRadius.setText(translate("draft","Distance"))
self.ui.radiusValue.setToolTip(translate("draft", "The offset distance"))
if real:
if self.force:
ray = self.newpoint.sub(v1)
@@ -3917,7 +3926,8 @@ class Trimex(Modifier):
ang1 = DraftVecUtils.angle(v2.sub(center))
ang2 = DraftVecUtils.angle(point.sub(center))
self.newpoint=Vector.add(center,DraftVecUtils.rotate(Vector(rad,0,0),-ang2))
self.ui.labelRadius.setText("Angle")
self.ui.labelRadius.setText(translate("draft","Angle"))
self.ui.radiusValue.setToolTip(translate("draft", "The offset angle"))
dist = math.degrees(-ang2)
# if ang1 > ang2: ang1,ang2 = ang2,ang1
#print("last calculated:",math.degrees(-ang1),math.degrees(-ang2))

View File

@@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>255</height>
<width>572</width>
<height>299</height>
</rect>
</property>
<property name="windowTitle">
@@ -49,55 +49,75 @@
<item>
<widget class="QWidget" name="widget" native="true">
<layout class="QGridLayout" name="gridLayout">
<item row="3" column="0" rowspan="2" colspan="2">
<widget class="QCheckBox" name="dwellEnabled">
<item row="7" column="1">
<widget class="QCheckBox" name="useTipLength">
<property name="text">
<string>Dwell</string>
<string>Use Tip Length</string>
</property>
</widget>
</item>
<item row="3" column="2" rowspan="2">
<widget class="Gui::InputField" name="dwellTime">
<item row="6" column="4">
<widget class="QLabel" name="dwellTimelabel">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>0 sec</string>
</property>
<property name="unit" stdset="0">
<string notr="true">sec</string>
<string>Time</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="Gui::InputField" name="retractHeight">
<property name="unit" stdset="0">
<string notr="true">mm</string>
<item row="1" column="4">
<widget class="QLabel" name="peckDepthLabel">
<property name="enabled">
<bool>false</bool>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_10">
<property name="text">
<string>Retract Height</string>
<string>Depth</string>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<item row="3" column="4">
<widget class="QLabel" name="retractLabel">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Retract</string>
</property>
</widget>
</item>
<item row="1" column="6">
<widget class="Gui::QuantitySpinBox" name="peckDepth">
<property name="enabled">
<bool>false</bool>
</property>
</widget>
</item>
<item row="1" column="1" colspan="2">
<widget class="QCheckBox" name="peckEnabled">
<property name="text">
<string>Peck</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="Gui::InputField" name="peckDepth">
<property name="unit" stdset="0">
<string notr="true">mm</string>
<item row="5" column="1" rowspan="2" colspan="2">
<widget class="QCheckBox" name="dwellEnabled">
<property name="text">
<string>Dwell</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QCheckBox" name="useTipLength">
<property name="text">
<string>Use Tip Length</string>
<item row="3" column="6">
<widget class="Gui::QuantitySpinBox" name="peckRetractHeight">
<property name="enabled">
<bool>false</bool>
</property>
</widget>
</item>
<item row="6" column="6">
<widget class="Gui::QuantitySpinBox" name="dwellTime">
<property name="enabled">
<bool>false</bool>
</property>
</widget>
</item>
@@ -121,18 +141,15 @@
</widget>
<customwidgets>
<customwidget>
<class>Gui::InputField</class>
<extends>QLineEdit</extends>
<header>Gui/InputField.h</header>
<class>Gui::QuantitySpinBox</class>
<extends>QDoubleSpinBox</extends>
<header>Gui/QuantitySpinBox.h</header>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>toolController</tabstop>
<tabstop>retractHeight</tabstop>
<tabstop>peckEnabled</tabstop>
<tabstop>peckDepth</tabstop>
<tabstop>dwellEnabled</tabstop>
<tabstop>dwellTime</tabstop>
<tabstop>useTipLength</tabstop>
</tabstops>
<resources/>

View File

@@ -43,7 +43,7 @@ __title__ = "Path Drilling Operation"
__author__ = "sliptonic (Brad Collette)"
__url__ = "http://www.freecadweb.org"
__doc__ = "Path Drilling operation."
__contributors__ = "russ4262 (Russell Johnson)"
__contributors__ = "russ4262 (Russell Johnson), IMBack!"
__created__ = "2014"
__scriptVersion__ = "1c testing"
__lastModified__ = "2019-06-25 14:49 CST"
@@ -77,10 +77,9 @@ class ObjectDrilling(PathCircularHoleBase.ObjectOp):
obj.addProperty("App::PropertyFloat", "DwellTime", "Drill", QtCore.QT_TRANSLATE_NOOP("App::Property", "The time to dwell between peck cycles"))
obj.addProperty("App::PropertyBool", "DwellEnabled", "Drill", QtCore.QT_TRANSLATE_NOOP("App::Property", "Enable dwell"))
obj.addProperty("App::PropertyBool", "AddTipLength", "Drill", QtCore.QT_TRANSLATE_NOOP("App::Property", "Calculate the tip length and subtract from final depth"))
obj.addProperty("App::PropertyEnumeration", "ReturnLevel", "Drill", QtCore.QT_TRANSLATE_NOOP("App::Property", "Controls how tool retracts Default=G98"))
obj.ReturnLevel = ['G98', 'G99'] # this is the direction that the Contour runs
obj.addProperty("App::PropertyDistance", "RetractHeight", "Drill", QtCore.QT_TRANSLATE_NOOP("App::Property", "The height where feed starts and height during retract tool when path is finished"))
obj.addProperty("App::PropertyEnumeration", "ReturnLevel", "Drill", QtCore.QT_TRANSLATE_NOOP("App::Property", "Controls how tool retracts Default=G99"))
obj.ReturnLevel = ['G99', 'G98'] # Canned Cycle Return Level
obj.addProperty("App::PropertyDistance", "RetractHeight", "Drill", QtCore.QT_TRANSLATE_NOOP("App::Property", "The height where feed starts and height during retract tool when path is finished while in a peck operation"))
# Rotation related properties
if not hasattr(obj, 'EnableRotation'):
@@ -115,14 +114,7 @@ class ObjectDrilling(PathCircularHoleBase.ObjectOp):
holes = PathUtils.sort_jobs(holes, ['x', 'y'])
self.commandlist.append(Path.Command('G90'))
self.commandlist.append(Path.Command(obj.ReturnLevel))
# ml: I'm not sure whey these were here, they seem redundant
# # rapid to first hole location, with spindle still retracted:
# p0 = holes[0]
# self.commandlist.append(Path.Command('G0', {'X': p0['x'], 'Y': p0['y'], 'F': self.horizRapid}))
# # move tool to clearance plane
# self.commandlist.append(Path.Command('G0', {'Z': obj.ClearanceHeight.Value, 'F': self.vertRapid}))
for p in holes:
cmd = "G81"
cmdParams = {}
@@ -172,10 +164,12 @@ class ObjectDrilling(PathCircularHoleBase.ObjectOp):
self.commandlist.append(Path.Command('G0', {axisOfRot: angle, 'F': self.axialRapid}))
self.commandlist.append(Path.Command('G0', {'X': p['x'], 'Y': p['y'], 'F': self.horizRapid}))
self.commandlist.append(Path.Command('G1', {'Z': p['stkTop'], 'F': self.vertFeed}))
# Perform and cancel canned drilling cycle
self.commandlist.append(Path.Command(cmd, params))
self.commandlist.append(Path.Command('G80'))
self.commandlist.append(Path.Command('G0', {'Z': obj.SafeHeight.Value}))
# shift axis and angle values
if obj.EnableRotation != 'Off':
@@ -186,9 +180,27 @@ class ObjectDrilling(PathCircularHoleBase.ObjectOp):
self.commandlist.append(Path.Command('G0', {'Z': obj.SafeHeight.Value, 'F': self.vertRapid}))
self.commandlist.append(Path.Command('G0', {lastAxis: 0.0, 'F': self.axialRapid}))
def opSetDefaultValues(self, obj, job):
'''opSetDefaultValues(obj, job) ... set default value for RetractHeight'''
obj.RetractHeight = 10.0
parentJob = PathUtils.findParentJob(obj)
if hasattr(parentJob.SetupSheet, 'RetractHeight'):
obj.RetractHeight = parentJob.SetupSheet.RetractHeight
elif self.applyExpression(obj, 'RetractHeight', 'OpStartDepth+1mm'):
obj.RetractHeight = 10
if hasattr(parentJob.SetupSheet, 'PeckDepth'):
obj.PeckDepth = parentJob.SetupSheet.PeckDepth
elif self.applyExpression(obj, 'PeckDepth', 'OpToolDiameter*0.75'):
obj.PeckDepth = 1
if hasattr(parentJob.SetupSheet, 'DwellTime'):
obj.DwellTime = parentJob.SetupSheet.DwellTime
else:
obj.DwellTime = 1
obj.ReverseDirection = False
obj.InverseAngle = False
obj.B_AxisErrorOverride = False
@@ -196,7 +208,6 @@ class ObjectDrilling(PathCircularHoleBase.ObjectOp):
# Initial setting for EnableRotation is taken from Job SetupSheet
# User may override on per-operation basis as needed.
parentJob = PathUtils.findParentJob(obj)
if hasattr(parentJob.SetupSheet, 'SetupEnableRotation'):
obj.EnableRotation = parentJob.SetupSheet.SetupEnableRotation
else:

View File

@@ -36,6 +36,7 @@ __title__ = "Path Drilling Operation UI."
__author__ = "sliptonic (Brad Collette)"
__url__ = "http://www.freecadweb.org"
__doc__ = "UI and Command for Path Drilling Operation."
__contributors__ = "IMBack!"
LOGLEVEL = False
@@ -48,17 +49,47 @@ else:
class TaskPanelOpPage(PathCircularHoleBaseGui.TaskPanelOpPage):
'''Controller for the drilling operation's page'''
def initPage(self, obj):
self.peckDepthSpinBox = PathGui.QuantitySpinBox(self.form.peckDepth, obj, 'PeckDepth')
self.peckRetractSpinBox = PathGui.QuantitySpinBox(self.form.peckRetractHeight, obj, 'RetractHeight')
self.dwellTimeSpinBox = PathGui.QuantitySpinBox(self.form.dwellTime, obj, 'DwellTime')
def registerSignalHandlers(self, obj):
self.form.peckEnabled.toggled.connect(self.form.peckDepth.setEnabled)
self.form.peckEnabled.toggled.connect(self.form.dwellEnabled.setDisabled)
self.form.dwellEnabled.toggled.connect(self.form.dwellTime.setEnabled)
self.form.dwellEnabled.toggled.connect(self.form.dwellTimelabel.setEnabled)
self.form.dwellEnabled.toggled.connect(self.form.peckEnabled.setDisabled)
self.form.peckRetractHeight.setEnabled(True)
self.form.retractLabel.setEnabled(True)
if self.form.peckEnabled.isChecked():
self.form.dwellEnabled.setEnabled(False)
self.form.peckDepth.setEnabled(True)
self.form.peckDepthLabel.setEnabled(True)
elif self.form.dwellEnabled.isChecked():
self.form.peckEnabled.setEnabled(False)
self.form.dwellTime.setEnabled(True)
self.form.dwellTimelabel.setEnabled(True)
def getForm(self):
'''getForm() ... return UI'''
return FreeCADGui.PySideUic.loadUi(":/panels/PageOpDrillingEdit.ui")
def updateQuantitySpinBoxes(self, index = None):
self.peckDepthSpinBox.updateSpinBox()
self.peckRetractSpinBox.updateSpinBox()
self.dwellTimeSpinBox.updateSpinBox()
def getFields(self, obj):
'''setFields(obj) ... update obj's properties with values from the UI'''
PathLog.track()
PathGui.updateInputField(obj, 'PeckDepth', self.form.peckDepth)
PathGui.updateInputField(obj, 'RetractHeight', self.form.retractHeight)
PathGui.updateInputField(obj, 'DwellTime', self.form.dwellTime)
self.peckDepthSpinBox.updateProperty()
self.peckRetractSpinBox.updateProperty()
self.dwellTimeSpinBox.updateProperty()
if obj.DwellEnabled != self.form.dwellEnabled.isChecked():
obj.DwellEnabled = self.form.dwellEnabled.isChecked()
@@ -72,10 +103,7 @@ class TaskPanelOpPage(PathCircularHoleBaseGui.TaskPanelOpPage):
def setFields(self, obj):
'''setFields(obj) ... update UI with obj properties' values'''
PathLog.track()
self.form.peckDepth.setText(FreeCAD.Units.Quantity(obj.PeckDepth.Value, FreeCAD.Units.Length).UserString)
self.form.retractHeight.setText(FreeCAD.Units.Quantity(obj.RetractHeight.Value, FreeCAD.Units.Length).UserString)
self.form.dwellTime.setText(str(obj.DwellTime))
self.updateQuantitySpinBoxes()
if obj.DwellEnabled:
self.form.dwellEnabled.setCheckState(QtCore.Qt.Checked)
@@ -98,7 +126,7 @@ class TaskPanelOpPage(PathCircularHoleBaseGui.TaskPanelOpPage):
'''getSignalsForUpdate(obj) ... return list of signals which cause the receiver to update the model'''
signals = []
signals.append(self.form.retractHeight.editingFinished)
signals.append(self.form.peckRetractHeight.editingFinished)
signals.append(self.form.peckDepth.editingFinished)
signals.append(self.form.dwellTime.editingFinished)
signals.append(self.form.dwellEnabled.stateChanged)
@@ -107,6 +135,10 @@ class TaskPanelOpPage(PathCircularHoleBaseGui.TaskPanelOpPage):
signals.append(self.form.toolController.currentIndexChanged)
return signals
def updateData(self, obj, prop):
if prop in ['PeckDepth', 'RetractHeight'] and not prop in ['Base', 'Disabled']:
self.updateQuantitySpinBoxes()
Command = PathOpGui.SetupOperation('Drilling',
PathDrilling.Create,

View File

@@ -122,6 +122,11 @@ The spin box gets bound to a given property and supports update in both directio
if self.valid:
return self.widget.property('expression')
return ''
def setMinimum(self, quantity):
if self.valid:
value = quantity.Value if hasattr(quantity, 'Value') else quantity
self.widget.setProperty('setMinimum', value)
def updateSpinBox(self, quantity=None):
'''updateSpinBox(quantity=None) ... update the display value of the spin box.

View File

@@ -354,6 +354,7 @@ class TaskPanelPage(object):
controllers = PathUtils.getToolControllers(self.obj)
labels = [c.Label for c in controllers]
combo.blockSignals(True)
combo.clear()
combo.addItems(labels)
combo.blockSignals(False)