Merge branch 'master' into HEAD
git-svn-id: https://free-cad.svn.sourceforge.net/svnroot/free-cad/trunk@5436 e8eeb9e2-ec13-0410-a4a9-efa5cf37419d
This commit is contained in:
commit
f53f1cee84
1
.gitattributes
vendored
1
.gitattributes
vendored
|
@ -11,5 +11,6 @@ mkinstalldirs export-ignore
|
|||
package export-ignore
|
||||
fc.sh export-ignore
|
||||
UpdateResources.bat export-ignore
|
||||
BuildVersion.bat export-ignore
|
||||
*.sln export-ignore
|
||||
WindowsInstaller export-ignore
|
||||
|
|
|
@ -467,3 +467,26 @@ if(FREECAD_MAINTAINERS_BUILD AND NOT WIN32)
|
|||
#ADD_CUSTOM_TARGET(DIST make package_source)
|
||||
|
||||
endif(FREECAD_MAINTAINERS_BUILD AND NOT WIN32)
|
||||
add_custom_target(dist-git
|
||||
COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_SOURCE_DIR}/src/Tools/makedist.py
|
||||
--srcdir=${CMAKE_SOURCE_DIR} --bindir=${CMAKE_BINARY_DIR}
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
)
|
||||
add_custom_target(distdfsg-git
|
||||
COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_SOURCE_DIR}/src/Tools/makedist.py
|
||||
--srcdir=${CMAKE_SOURCE_DIR} --bindir=${CMAKE_BINARY_DIR} --dfsg
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
)
|
||||
if(CMAKE_COMPILER_IS_GNUCXX OR MINGW)
|
||||
add_custom_target(distcheck-git
|
||||
COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_SOURCE_DIR}/src/Tools/makedist.py
|
||||
--srcdir=${CMAKE_SOURCE_DIR} --bindir=${CMAKE_BINARY_DIR} --check
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
)
|
||||
add_custom_target(distcheckdfsg-git
|
||||
COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_SOURCE_DIR}/src/Tools/makedist.py
|
||||
--srcdir=${CMAKE_SOURCE_DIR} --bindir=${CMAKE_BINARY_DIR} --dfsg --check
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
)
|
||||
endif(CMAKE_COMPILER_IS_GNUCXX OR MINGW)
|
||||
|
||||
|
|
8
src/3rdParty/CMakeLists.txt
vendored
8
src/3rdParty/CMakeLists.txt
vendored
|
@ -22,9 +22,13 @@ elseif(FREECAD_BUILD_GUI AND FREECAD_LIBPACK_CHECKFILE7X)
|
|||
elseif(FREECAD_BUILD_GUI)
|
||||
find_path(COIN_VERSION3 Inventor/scxml/ScXML.h ${COIN3D_INCLUDE_DIR})
|
||||
if (COIN_VERSION3)
|
||||
add_subdirectory(Pivy-0.5)
|
||||
if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/Pivy-0.5)
|
||||
add_subdirectory(Pivy-0.5)
|
||||
endif (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/Pivy-0.5)
|
||||
else (COIN_VERSION3)
|
||||
add_subdirectory(Pivy)
|
||||
if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/Pivy)
|
||||
add_subdirectory(Pivy)
|
||||
endif (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/Pivy)
|
||||
endif(COIN_VERSION3)
|
||||
endif(FREECAD_BUILD_GUI AND FREECAD_LIBPACK_CHECKFILE6X)
|
||||
|
||||
|
|
|
@ -1028,12 +1028,18 @@ void Application::initConfig(int argc, char ** argv)
|
|||
// only for 'BuildVersionMajor'.
|
||||
if (App::Application::Config().find("BuildVersionMajor") == App::Application::Config().end()) {
|
||||
std::stringstream str; str << FCVersionMajor << "." << FCVersionMinor;
|
||||
App::Application::Config()["ExeVersion"] = str.str();
|
||||
App::Application::Config()["BuildVersionMajor"] = FCVersionMajor;
|
||||
App::Application::Config()["BuildVersionMinor"] = FCVersionMinor;
|
||||
App::Application::Config()["BuildRevision"] = FCRevision;
|
||||
App::Application::Config()["BuildRepositoryURL"] = FCRepositoryURL;
|
||||
App::Application::Config()["BuildRevisionDate"] = FCCurrentDateT;
|
||||
App::Application::Config()["ExeVersion" ] = str.str();
|
||||
App::Application::Config()["BuildVersionMajor" ] = FCVersionMajor;
|
||||
App::Application::Config()["BuildVersionMinor" ] = FCVersionMinor;
|
||||
App::Application::Config()["BuildRevision" ] = FCRevision;
|
||||
App::Application::Config()["BuildRepositoryURL" ] = FCRepositoryURL;
|
||||
App::Application::Config()["BuildRevisionDate" ] = FCRevisionDate;
|
||||
#if defined(FCRepositoryHash)
|
||||
App::Application::Config()["BuildRevisionHash" ] = FCRepositoryHash;
|
||||
#endif
|
||||
#if defined(FCRepositoryBranch)
|
||||
App::Application::Config()["BuildRevisionBranch"] = FCRepositoryBranch;
|
||||
#endif
|
||||
}
|
||||
|
||||
_argc = argc;
|
||||
|
|
|
@ -68,6 +68,7 @@ if(SWIG_FOUND)
|
|||
add_definitions(-DHAVE_SWIG=1)
|
||||
endif(SWIG_FOUND)
|
||||
|
||||
if (EXISTS ${CMAKE_SOURCE_DIR}/src/zipios++)
|
||||
SET(zipios_SRCS
|
||||
../zipios++/backbuffer.h
|
||||
../zipios++/basicentry.cpp
|
||||
|
@ -121,6 +122,12 @@ SET(zipios_SRCS
|
|||
../zipios++/zipoutputstream.h
|
||||
)
|
||||
SOURCE_GROUP("zipios" FILES ${zipios_SRCS})
|
||||
else (EXISTS ${CMAKE_SOURCE_DIR}/src/zipios++)
|
||||
set(FreeCADBase_LIBS
|
||||
${FreeCADBase_LIBS}
|
||||
-lzipios
|
||||
)
|
||||
endif (EXISTS ${CMAKE_SOURCE_DIR}/src/zipios++)
|
||||
|
||||
SET(pycxx_SRCS
|
||||
../CXX/Config.hxx
|
||||
|
@ -148,11 +155,11 @@ SET(FreeCADBase_XML_SRCS
|
|||
VectorPy.xml
|
||||
)
|
||||
SOURCE_GROUP("XML" FILES ${FreeCADBase_XML_SRCS})
|
||||
|
||||
set(FreeCADBase_MOC_HDRS
|
||||
FutureWatcherProgress.h
|
||||
)
|
||||
fc_wrap_cpp(FreeCADBase_MOC_SRCS ${FreeCADBase_MOC_HDRS})
|
||||
|
||||
set(FreeCADBase_MOC_HDRS
|
||||
FutureWatcherProgress.h
|
||||
)
|
||||
fc_wrap_cpp(FreeCADBase_MOC_SRCS ${FreeCADBase_MOC_HDRS})
|
||||
|
||||
SET(FreeCADBase_UNITAPI_SRCS
|
||||
UnitsApi.cpp
|
||||
|
|
|
@ -176,8 +176,11 @@ std::string FileInfo::getTempFileName(const char* FileName, const char* Path)
|
|||
else
|
||||
std::strcat(buf, "/fileXXXXXX");
|
||||
|
||||
/*int id =*/ (void) mkstemp(buf);
|
||||
//FILE* file = fdopen(id, "w");
|
||||
int id = mkstemp(buf);
|
||||
if (id > -1) {
|
||||
FILE* file = fdopen(id, "w");
|
||||
fclose(file);
|
||||
}
|
||||
return std::string(buf);
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -1,18 +1,10 @@
|
|||
|
||||
/// Version Number
|
||||
// Version Number
|
||||
#define FCVersionMajor "0"
|
||||
#define FCVersionMinor "13"
|
||||
#define FCVersionName "Vulcan"
|
||||
|
||||
#define FCRevision "$WCREV$" //Highest committed revision number
|
||||
#define FCRevisionDate "$WCDATE$" //Date of highest committed revision
|
||||
#define FCRevisionRange "$WCRANGE$" //Update revision range
|
||||
#define FCRepositoryURL "$WCURL$" //Repository URL of the working copy
|
||||
#define FCCurrentDateT "$WCNOW$" //Current system date & time
|
||||
|
||||
//Placeholders of the form "$WCxxx?TrueText:FalseText$" are replaced with
|
||||
//TrueText if the tested condition is true, and FalseText if false.
|
||||
|
||||
#define FCScrClean "$WCMODS?Src modified:Src not modified$" //True if local modifications found
|
||||
#define FCScrMixed "$WCMIXED?Src mixed:Src not mixed$" //True if mixed update revisions found
|
||||
|
||||
|
|
|
@ -16,13 +16,17 @@
|
|||
<property name="modal">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<layout class="QGridLayout">
|
||||
<property name="margin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0" colspan="3">
|
||||
<widget class="QLabel" name="labelSplashPicture">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<spacer>
|
||||
<property name="orientation">
|
||||
|
@ -36,15 +40,18 @@
|
|||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="0" column="0" colspan="3">
|
||||
<widget class="QLabel" name="labelSplashPicture">
|
||||
<property name="text">
|
||||
<string/>
|
||||
<item row="2" column="0">
|
||||
<spacer>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>31</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<layout class="QVBoxLayout">
|
||||
|
@ -161,6 +168,34 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="labelBranch">
|
||||
<property name="text">
|
||||
<string notr="true">Branch</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<widget class="QLabel" name="labelBuildBranch">
|
||||
<property name="text">
|
||||
<string notr="true"><html><head><meta name="qrichtext" content="1" /></head><body style=" white-space: pre-wrap; font-family:MS Shell Dlg 2; font-size:7.8pt; font-weight:400; font-style:normal; text-decoration:none;"><p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;"><span style=" font-weight:600;">Unknown</span></p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<widget class="QLabel" name="labelBuildHash">
|
||||
<property name="text">
|
||||
<string notr="true"><html><head><meta name="qrichtext" content="1" /></head><body style=" white-space: pre-wrap; font-family:MS Shell Dlg 2; font-size:7.8pt; font-weight:400; font-style:normal; text-decoration:none;"><p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;"><span style=" font-weight:600;">Unknown</span></p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<widget class="QLabel" name="labelHash">
|
||||
<property name="text">
|
||||
<string notr="true">Hash</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
|
@ -178,19 +213,6 @@
|
|||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<spacer>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>31</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<spacer>
|
||||
<property name="orientation">
|
||||
|
@ -219,6 +241,13 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="copyButton">
|
||||
<property name="text">
|
||||
<string>Copy to clipboard</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer>
|
||||
<property name="orientation">
|
||||
|
@ -239,19 +268,6 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>181</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
|
@ -264,7 +280,7 @@
|
|||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources>
|
||||
<include location="Icons/resource.qrc"/>
|
||||
<include location="../../../FreeCAD/src/Gui/Icons/resource.qrc"/>
|
||||
</resources>
|
||||
<connections>
|
||||
<connection>
|
||||
|
|
|
@ -23,8 +23,11 @@
|
|||
|
||||
#include "PreCompiled.h"
|
||||
#ifndef _PreComp_
|
||||
# include <QApplication>
|
||||
# include <QClipboard>
|
||||
# include <QMutex>
|
||||
# include <QSysInfo>
|
||||
# include <QTextStream>
|
||||
# include <QWaitCondition>
|
||||
#endif
|
||||
|
||||
|
@ -248,18 +251,18 @@ static QString getPlatform()
|
|||
|
||||
void AboutDialog::setupLabels()
|
||||
{
|
||||
QString exeName = QString::fromAscii(App::Application::Config()["ExeName"].c_str());
|
||||
std::map<std::string,std::string>& cfg = App::Application::Config();
|
||||
std::map<std::string,std::string>::iterator it = cfg.find("WindowTitle");
|
||||
if (it != cfg.end())
|
||||
std::map<std::string, std::string>& config = App::Application::Config();
|
||||
QString exeName = QString::fromAscii(config["ExeName"].c_str());
|
||||
std::map<std::string,std::string>::iterator it = config.find("WindowTitle");
|
||||
if (it != config.end())
|
||||
exeName = QString::fromUtf8(it->second.c_str());
|
||||
QString banner = QString::fromUtf8(App::Application::Config()["ConsoleBanner"].c_str());
|
||||
QString banner = QString::fromUtf8(config["ConsoleBanner"].c_str());
|
||||
banner = banner.left( banner.indexOf(QLatin1Char('\n')) );
|
||||
QString major = QString::fromAscii(App::Application::Config()["BuildVersionMajor"].c_str());
|
||||
QString minor = QString::fromAscii(App::Application::Config()["BuildVersionMinor"].c_str());
|
||||
QString build = QString::fromAscii(App::Application::Config()["BuildRevision"].c_str());
|
||||
QString disda = QString::fromAscii(App::Application::Config()["BuildRevisionDate"].c_str());
|
||||
QString mturl = QString::fromAscii(App::Application::Config()["MaintainerUrl"].c_str());
|
||||
QString major = QString::fromAscii(config["BuildVersionMajor"].c_str());
|
||||
QString minor = QString::fromAscii(config["BuildVersionMinor"].c_str());
|
||||
QString build = QString::fromAscii(config["BuildRevision"].c_str());
|
||||
QString disda = QString::fromAscii(config["BuildRevisionDate"].c_str());
|
||||
QString mturl = QString::fromAscii(config["MaintainerUrl"].c_str());
|
||||
|
||||
QString author = ui->labelAuthor->text();
|
||||
author.replace(QString::fromAscii("Unknown Application"), exeName);
|
||||
|
@ -283,10 +286,56 @@ void AboutDialog::setupLabels()
|
|||
platform.replace(QString::fromAscii("Unknown"),
|
||||
QString::fromAscii("%1 (%2-bit)").arg(getPlatform()).arg(QSysInfo::WordSize));
|
||||
ui->labelBuildPlatform->setText(platform);
|
||||
|
||||
// branch name
|
||||
it = config.find("BuildRevisionBranch");
|
||||
if (it != config.end()) {
|
||||
QString branch = ui->labelBuildBranch->text();
|
||||
branch.replace(QString::fromAscii("Unknown"), QString::fromAscii(it->second.c_str()));
|
||||
ui->labelBuildBranch->setText(branch);
|
||||
}
|
||||
else {
|
||||
ui->labelBranch->hide();
|
||||
ui->labelBuildBranch->hide();
|
||||
}
|
||||
|
||||
// hash id
|
||||
it = config.find("BuildRevisionHash");
|
||||
if (it != config.end()) {
|
||||
QString hash = ui->labelBuildHash->text();
|
||||
hash.replace(QString::fromAscii("Unknown"), QString::fromAscii(it->second.c_str()));
|
||||
ui->labelBuildHash->setText(hash);
|
||||
}
|
||||
else {
|
||||
ui->labelHash->hide();
|
||||
ui->labelBuildHash->hide();
|
||||
}
|
||||
}
|
||||
|
||||
void AboutDialog::on_licenseButton_clicked()
|
||||
{
|
||||
}
|
||||
|
||||
void AboutDialog::on_copyButton_clicked()
|
||||
{
|
||||
QString data;
|
||||
QTextStream str(&data);
|
||||
std::map<std::string, std::string>& config = App::Application::Config();
|
||||
std::map<std::string,std::string>::iterator it;
|
||||
|
||||
QString major = QString::fromAscii(config["BuildVersionMajor"].c_str());
|
||||
QString minor = QString::fromAscii(config["BuildVersionMinor"].c_str());
|
||||
QString build = QString::fromAscii(config["BuildRevision"].c_str());
|
||||
str << "Version: " << major << "." << minor << "." << build << endl;
|
||||
it = config.find("BuildRevisionBranch");
|
||||
if (it != config.end())
|
||||
str << "Branch: " << it->second.c_str() << endl;
|
||||
it = config.find("BuildRevisionHash");
|
||||
if (it != config.end())
|
||||
str << "Hash: " << it->second.c_str() << endl;
|
||||
|
||||
QClipboard* cb = QApplication::clipboard();
|
||||
cb->setText(data);
|
||||
}
|
||||
|
||||
#include "moc_Splashscreen.cpp"
|
||||
|
|
|
@ -85,6 +85,7 @@ protected:
|
|||
|
||||
protected Q_SLOTS:
|
||||
virtual void on_licenseButton_clicked();
|
||||
virtual void on_copyButton_clicked();
|
||||
|
||||
private:
|
||||
Ui_AboutApplication* ui;
|
||||
|
|
|
@ -140,6 +140,7 @@ class ComponentTaskPanel:
|
|||
QtCore.QObject.connect(self.addButton, QtCore.SIGNAL("clicked()"), self.addElement)
|
||||
QtCore.QObject.connect(self.delButton, QtCore.SIGNAL("clicked()"), self.removeElement)
|
||||
QtCore.QObject.connect(self.tree, QtCore.SIGNAL("itemClicked(QTreeWidgetItem*,int)"), self.check)
|
||||
QtCore.QObject.connect(self.tree, QtCore.SIGNAL("itemDoubleClicked(QTreeWidgetItem *,int)"), self.editObject)
|
||||
self.update()
|
||||
|
||||
def isAllowedAlterSelection(self):
|
||||
|
@ -224,7 +225,21 @@ class ComponentTaskPanel:
|
|||
if self.obj:
|
||||
self.obj.ViewObject.finishEditing()
|
||||
return True
|
||||
|
||||
|
||||
def editObject(self,wid,col):
|
||||
if wid.parent():
|
||||
obj = FreeCAD.ActiveDocument.getObject(str(wid.text(0)))
|
||||
if obj:
|
||||
self.obj.ViewObject.Transparency = 80
|
||||
self.obj.ViewObject.Selectable = False
|
||||
obj.ViewObject.show()
|
||||
self.accept()
|
||||
if obj.isDerivedFrom("Sketcher::SketchObject"):
|
||||
FreeCADGui.activateWorkbench("SketcherWorkbench")
|
||||
FreeCAD.ArchObserver = ArchSelectionObserver(self.obj,obj)
|
||||
FreeCADGui.Selection.addObserver(FreeCAD.ArchObserver)
|
||||
FreeCADGui.ActiveDocument.setEdit(obj.Name,0)
|
||||
|
||||
def retranslateUi(self, TaskPanel):
|
||||
TaskPanel.setWindowTitle(QtGui.QApplication.translate("Arch", "Components", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.delButton.setText(QtGui.QApplication.translate("Arch", "Remove", None, QtGui.QApplication.UnicodeUTF8))
|
||||
|
@ -251,8 +266,7 @@ class Component:
|
|||
obj.Proxy = self
|
||||
self.Type = "Component"
|
||||
self.Subvolume = None
|
||||
|
||||
|
||||
|
||||
class ViewProviderComponent:
|
||||
"A default View Provider for Component objects"
|
||||
def __init__(self,vobj):
|
||||
|
@ -295,4 +309,18 @@ class ViewProviderComponent:
|
|||
def unsetEdit(self,vobj,mode):
|
||||
FreeCADGui.Control.closeDialog()
|
||||
return
|
||||
|
||||
|
||||
class ArchSelectionObserver:
|
||||
def __init__(self,origin,watched):
|
||||
self.origin = origin
|
||||
self.watched = watched
|
||||
def addSelection(self,document, object, element, position):
|
||||
if object == self.watched.Name:
|
||||
if not element:
|
||||
print "closing Sketch edit"
|
||||
self.origin.ViewObject.Transparency = 0
|
||||
self.origin.ViewObject.Selectable = True
|
||||
self.watched.ViewObject.hide()
|
||||
FreeCADGui.activateWorkbench("ArchWorkbench")
|
||||
FreeCADGui.Selection.removeObserver(FreeCAD.ArchObserver)
|
||||
del FreeCAD.ArchObserver
|
||||
|
|
|
@ -256,18 +256,11 @@ def formatObject(target,origin=None):
|
|||
if "ShapeColor" in obrep.PropertiesList: obrep.ShapeColor = fcol
|
||||
else:
|
||||
matchrep = origin.ViewObject
|
||||
if ("LineWidth" in obrep.PropertiesList) and \
|
||||
("LineWidth" in matchrep.PropertiesList):
|
||||
obrep.LineWidth = matchrep.LineWidth
|
||||
if ("PointColor" in obrep.PropertiesList) and \
|
||||
("PointColor" in matchrep.PropertiesList):
|
||||
obrep.PointColor = matchrep.PointColor
|
||||
if ("LineColor" in obrep.PropertiesList) and \
|
||||
("LineColor" in matchrep.PropertiesList):
|
||||
obrep.LineColor = matchrep.LineColor
|
||||
if ("ShapeColor" in obrep.PropertiesList) and \
|
||||
("ShapeColor" in matchrep.PropertiesList):
|
||||
obrep.ShapeColor = matchrep.ShapeColor
|
||||
for p in matchrep.PropertiesList:
|
||||
if not p in ["DisplayMode","BoundingBox","Proxy","RootNode"]:
|
||||
if p in obrep.PropertiesList:
|
||||
val = getattr(matchrep,p)
|
||||
setattr(obrep,p,val)
|
||||
if matchrep.DisplayMode in obrep.listDisplayModes():
|
||||
obrep.DisplayMode = matchrep.DisplayMode
|
||||
|
||||
|
@ -516,48 +509,52 @@ def makeText(stringslist,point=Vector(0,0,0),screen=False):
|
|||
select(obj)
|
||||
return obj
|
||||
|
||||
def makeCopy(obj):
|
||||
def makeCopy(obj,force=None,reparent=False):
|
||||
'''makeCopy(object): returns an exact copy of an object'''
|
||||
if getType(obj) == "Rectangle":
|
||||
if (getType(obj) == "Rectangle") or (force == "Rectangle"):
|
||||
newobj = FreeCAD.ActiveDocument.addObject(obj.Type,getRealName(obj.Name))
|
||||
_Rectangle(newobj)
|
||||
_ViewProviderRectangle(newobj.ViewObject)
|
||||
elif getType(obj) == "Wire":
|
||||
elif (getType(obj) == "Dimension") or (force == "Dimension"):
|
||||
newobj = FreeCAD.ActiveDocument.addObject(obj.Type,getRealName(obj.Name))
|
||||
_Dimension(newobj)
|
||||
_ViewProviderDimension(newobj.ViewObject)
|
||||
elif (getType(obj) == "Wire") or (force == "Wire"):
|
||||
newobj = FreeCAD.ActiveDocument.addObject(obj.Type,getRealName(obj.Name))
|
||||
_Wire(newobj)
|
||||
_ViewProviderWire(newobj.ViewObject)
|
||||
elif getType(obj) == "Circle":
|
||||
elif (getType(obj) == "Circle") or (force == "Circle"):
|
||||
newobj = FreeCAD.ActiveDocument.addObject(obj.Type,getRealName(obj.Name))
|
||||
_Circle(newobj)
|
||||
_ViewProviderCircle(newobj.ViewObject)
|
||||
elif getType(obj) == "Polygon":
|
||||
_ViewProviderDraft(newobj.ViewObject)
|
||||
elif (getType(obj) == "Polygon") or (force == "Polygon"):
|
||||
newobj = FreeCAD.ActiveDocument.addObject(obj.Type,getRealName(obj.Name))
|
||||
_Polygon(newobj)
|
||||
_ViewProviderPolygon(newobj.ViewObject)
|
||||
elif getType(obj) == "BSpline":
|
||||
elif (getType(obj) == "BSpline") or (force == "BSpline"):
|
||||
newobj = FreeCAD.ActiveDocument.addObject(obj.Type,getRealName(obj.Name))
|
||||
_BSpline(newobj)
|
||||
_ViewProviderBSpline(newobj.ViewObject)
|
||||
elif getType(obj) == "Block":
|
||||
elif (getType(obj) == "Block") or (force == "BSpline"):
|
||||
newobj = FreeCAD.ActiveDocument.addObject(obj.Type,getRealName(obj.Name))
|
||||
_Block(newobj)
|
||||
_ViewProviderDraftPart(newobj.ViewObject)
|
||||
elif getType(obj) == "Structure":
|
||||
elif (getType(obj) == "Structure") or (force == "Structure"):
|
||||
import ArchStructure
|
||||
newobj = FreeCAD.ActiveDocument.addObject(obj.Type,getRealName(obj.Name))
|
||||
ArchStructure._Structure(newobj)
|
||||
ArchStructure._ViewProviderStructure(newobj.ViewObject)
|
||||
elif getType(obj) == "Wall":
|
||||
elif (getType(obj) == "Wall") or (force == "Wall"):
|
||||
import ArchWall
|
||||
newobj = FreeCAD.ActiveDocument.addObject(obj.Type,getRealName(obj.Name))
|
||||
ArchWall._Wall(newobj)
|
||||
ArchWall._ViewProviderWall(newobj.ViewObject)
|
||||
elif getType(obj) == "Window":
|
||||
elif (getType(obj) == "Window") or (force == "Window"):
|
||||
import ArchWindow
|
||||
newobj = FreeCAD.ActiveDocument.addObject(obj.Type,getRealName(obj.Name))
|
||||
ArchWindow._Window(newobj)
|
||||
Archwindow._ViewProviderWindow(newobj.ViewObject)
|
||||
elif getType(obj) == "Cell":
|
||||
elif (getType(obj) == "Cell") or (force == "Cell"):
|
||||
import ArchCell
|
||||
newobj = FreeCAD.ActiveDocument.addObject(obj.Type,getRealName(obj.Name))
|
||||
ArchCell._Cell(newobj)
|
||||
|
@ -569,8 +566,19 @@ def makeCopy(obj):
|
|||
print "Error: Object type cannot be copied"
|
||||
return None
|
||||
for p in obj.PropertiesList:
|
||||
if p in newobj.PropertiesList:
|
||||
setattr(newobj,p,obj.getPropertyByName(p))
|
||||
if not p in ["Proxy"]:
|
||||
if p in newobj.PropertiesList:
|
||||
setattr(newobj,p,obj.getPropertyByName(p))
|
||||
if reparent:
|
||||
parents = obj.InList
|
||||
if parents:
|
||||
for par in parents:
|
||||
if par.Type == "App::DocumentObjectGroup":
|
||||
par.addObject(newobj)
|
||||
else:
|
||||
for prop in par.PropertiesList:
|
||||
if getattr(par,prop) == obj:
|
||||
setattr(par,prop,newobj)
|
||||
formatObject(newobj,obj)
|
||||
return newobj
|
||||
|
||||
|
@ -685,7 +693,7 @@ def move(objectslist,vector,copy=False):
|
|||
if copy:
|
||||
newobj = FreeCAD.ActiveDocument.addObject("App::FeaturePython",getRealName(obj.Name))
|
||||
_Dimension(newobj)
|
||||
_DimensionViewProvider(newobj.ViewObject)
|
||||
_ViewProviderDimension(newobj.ViewObject)
|
||||
else:
|
||||
newobj = obj
|
||||
newobj.Start = obj.Start.add(vector)
|
||||
|
@ -1401,6 +1409,57 @@ def clone(obj,delta=None):
|
|||
if delta:
|
||||
cl.Placement.move(delta)
|
||||
return cl
|
||||
|
||||
def heal(objlist=None,delete=True,reparent=True):
|
||||
'''heal([objlist],[delete],[reparent]) - recreates Draft objects that are damaged,
|
||||
for example if created from an earlier version. If delete is True,
|
||||
the damaged objects are deleted (default). If ran without arguments, all the objects
|
||||
in the document will be healed if they are damaged. If reparent is True (default),
|
||||
new objects go at the very same place in the tree than their original.'''
|
||||
|
||||
if not objlist:
|
||||
objlist = FreeCAD.ActiveDocument.Objects
|
||||
print "Healing whole document..."
|
||||
|
||||
if not isinstance(objlist,list):
|
||||
objlist = [objlist]
|
||||
|
||||
dellist = []
|
||||
got = False
|
||||
|
||||
for obj in objlist:
|
||||
dtype = getType(obj)
|
||||
ftype = obj.Type
|
||||
if ftype in ["Part::FeaturePython","App::FeaturePython"]:
|
||||
if obj.ViewObject.Proxy == 1 and dtype in ["Unknown","Part"]:
|
||||
got = True
|
||||
dellist.append(obj.Name)
|
||||
props = obj.PropertiesList
|
||||
if ("Dimline" in props) and ("Start" in props):
|
||||
print "Healing " + obj.Name + " of type Dimension"
|
||||
nobj = makeCopy(obj,force="Dimension",reparent=reparent)
|
||||
elif ("Height" in props) and ("Length" in props):
|
||||
print "Healing " + obj.Name + " of type Rectangle"
|
||||
nobj = makeCopy(obj,force="Rectangle",reparent=reparent)
|
||||
elif ("Points" in props) and ("Closed" in props):
|
||||
print "Healing " + obj.Name + " of type Wire"
|
||||
nobj = makeCopy(obj,force="Wire",reparent=reparent)
|
||||
elif ("Radius" in props) and ("FirstAngle" in props):
|
||||
print "Healing " + obj.Name + " of type Circle"
|
||||
nobj = makeCopy(obj,force="Circle",reparent=reparent)
|
||||
else:
|
||||
dellist.pop()
|
||||
print "Object " + obj.Name + " is not healable"
|
||||
|
||||
if not got:
|
||||
print "No object seems to need healing"
|
||||
else:
|
||||
print "Healed ",len(dellist)," objects"
|
||||
|
||||
if dellist and delete:
|
||||
for n in dellist:
|
||||
FreeCAD.ActiveDocument.removeObject(n)
|
||||
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Python Features definitions
|
||||
|
@ -1539,10 +1598,13 @@ class _ViewProviderDimension:
|
|||
if hasattr(obj.ViewObject,"DisplayMode"):
|
||||
if obj.ViewObject.DisplayMode == "3D":
|
||||
offset = fcvec.neg(offset)
|
||||
if obj.ViewObject.TextPosition == Vector(0,0,0):
|
||||
tbase = midpoint.add(offset)
|
||||
if hasattr(obj.ViewObject,"TextPosition"):
|
||||
if obj.ViewObject.TextPosition == Vector(0,0,0):
|
||||
tbase = midpoint.add(offset)
|
||||
else:
|
||||
tbase = obj.ViewObject.TextPosition
|
||||
else:
|
||||
tbase = obj.ViewObject.TextPosition
|
||||
tbase = midpoint.add(offset)
|
||||
rot = FreeCAD.Placement(fcvec.getPlaneRotation(u,v,norm)).Rotation.Q
|
||||
return p1,p2,p3,p4,tbase,norm,rot
|
||||
|
||||
|
@ -1966,6 +2028,7 @@ class _Rectangle:
|
|||
def __init__(self, obj):
|
||||
obj.addProperty("App::PropertyDistance","Length","Base","Length of the rectangle")
|
||||
obj.addProperty("App::PropertyDistance","Height","Base","Height of the rectange")
|
||||
obj.addProperty("App::PropertyDistance","FilletRadius","Base","Radius to use to fillet the corners")
|
||||
obj.Proxy = self
|
||||
obj.Length=1
|
||||
obj.Height=1
|
||||
|
@ -1980,12 +2043,18 @@ class _Rectangle:
|
|||
|
||||
def createGeometry(self,fp):
|
||||
import Part
|
||||
from draftlibs import fcgeo
|
||||
plm = fp.Placement
|
||||
p1 = Vector(0,0,0)
|
||||
p2 = Vector(p1.x+fp.Length,p1.y,p1.z)
|
||||
p3 = Vector(p1.x+fp.Length,p1.y+fp.Height,p1.z)
|
||||
p4 = Vector(p1.x,p1.y+fp.Height,p1.z)
|
||||
shape = Part.makePolygon([p1,p2,p3,p4,p1])
|
||||
if "FilletRadius" in fp.PropertiesList:
|
||||
if fp.FilletRadius != 0:
|
||||
w = fcgeo.filletWire(shape,fp.FilletRadius)
|
||||
if w:
|
||||
shape = w
|
||||
shape = Part.Face(shape)
|
||||
fp.Shape = shape
|
||||
fp.Placement = plm
|
||||
|
@ -2017,9 +2086,9 @@ class _Circle:
|
|||
"The Circle object"
|
||||
|
||||
def __init__(self, obj):
|
||||
obj.addProperty("App::PropertyAngle","FirstAngle","Arc",
|
||||
obj.addProperty("App::PropertyAngle","FirstAngle","Base",
|
||||
"Start angle of the arc")
|
||||
obj.addProperty("App::PropertyAngle","LastAngle","Arc",
|
||||
obj.addProperty("App::PropertyAngle","LastAngle","Base",
|
||||
"End angle of the arc (for a full circle, give it same value as First Angle)")
|
||||
obj.addProperty("App::PropertyDistance","Radius","Base",
|
||||
"Radius of the circle")
|
||||
|
@ -2060,6 +2129,7 @@ class _Wire:
|
|||
"The start point of this line")
|
||||
obj.addProperty("App::PropertyVector","End","Base",
|
||||
"The end point of this line")
|
||||
obj.addProperty("App::PropertyDistance","FilletRadius","Base","Radius to use to fillet the corners")
|
||||
obj.Proxy = self
|
||||
obj.Closed = False
|
||||
self.Type = "Wire"
|
||||
|
@ -2068,7 +2138,7 @@ class _Wire:
|
|||
self.createGeometry(fp)
|
||||
|
||||
def onChanged(self, fp, prop):
|
||||
if prop in ["Points","Closed","Base","Tool"]:
|
||||
if prop in ["Points","Closed","Base","Tool","FilletRadius"]:
|
||||
self.createGeometry(fp)
|
||||
if prop == "Points":
|
||||
if fp.Start != fp.Points[0]:
|
||||
|
@ -2121,6 +2191,11 @@ class _Wire:
|
|||
fp.Points.pop()
|
||||
if fp.Closed and (len(fp.Points) > 2):
|
||||
shape = Part.makePolygon(fp.Points+[fp.Points[0]])
|
||||
if "FilletRadius" in fp.PropertiesList:
|
||||
if fp.FilletRadius != 0:
|
||||
w = fcgeo.filletWire(shape,fp.FilletRadius)
|
||||
if w:
|
||||
shape = w
|
||||
shape = Part.Face(shape)
|
||||
else:
|
||||
edges = []
|
||||
|
@ -2130,6 +2205,11 @@ class _Wire:
|
|||
edges.append(Part.Line(lp,p).toShape())
|
||||
lp = p
|
||||
shape = Part.Wire(edges)
|
||||
if "FilletRadius" in fp.PropertiesList:
|
||||
if fp.FilletRadius != 0:
|
||||
w = fcgeo.filletWire(shape,fp.FilletRadius)
|
||||
if w:
|
||||
shape = w
|
||||
fp.Shape = shape
|
||||
fp.Placement = plm
|
||||
|
||||
|
@ -2178,6 +2258,7 @@ class _Polygon:
|
|||
obj.addProperty("App::PropertyInteger","FacesNumber","Base","Number of faces")
|
||||
obj.addProperty("App::PropertyDistance","Radius","Base","Radius of the control circle")
|
||||
obj.addProperty("App::PropertyEnumeration","DrawMode","Base","How the polygon must be drawn from the control circle")
|
||||
obj.addProperty("App::PropertyDistance","FilletRadius","Base","Radius to use to fillet the corners")
|
||||
obj.DrawMode = ['inscribed','circumscribed']
|
||||
obj.FacesNumber = 3
|
||||
obj.Radius = 1
|
||||
|
@ -2193,6 +2274,7 @@ class _Polygon:
|
|||
|
||||
def createGeometry(self,fp):
|
||||
import Part
|
||||
from draftlibs import fcgeo
|
||||
plm = fp.Placement
|
||||
angle = (math.pi*2)/fp.FacesNumber
|
||||
if fp.DrawMode == 'inscribed':
|
||||
|
@ -2205,6 +2287,11 @@ class _Polygon:
|
|||
pts.append(Vector(delta*math.cos(ang),delta*math.sin(ang),0))
|
||||
pts.append(pts[0])
|
||||
shape = Part.makePolygon(pts)
|
||||
if "FilletRadius" in fp.PropertiesList:
|
||||
if fp.FilletRadius != 0:
|
||||
w = fcgeo.filletWire(shape,fp.FilletRadius)
|
||||
if w:
|
||||
shape = w
|
||||
shape = Part.Face(shape)
|
||||
fp.Shape = shape
|
||||
fp.Placement = plm
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -356,6 +356,43 @@ If color mapping is choosed, you must choose a color mapping file containing a t
|
|||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_9">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Export Style</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Gui::PrefComboBox" name="svg_export_style_combobox">
|
||||
<property name="toolTip">
|
||||
<string>Style of SVG file to write when exporting a Sketch.</string>
|
||||
</property>
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="prefEntry" stdset="0">
|
||||
<cstring>svg_export_style</cstring>
|
||||
</property>
|
||||
<property name="prefPath" stdset="0">
|
||||
<cstring>Mod/Draft</cstring>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Translated (for print & display)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Raw (for CAM)</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
|
@ -1195,6 +1195,280 @@ def arcFromSpline(edge):
|
|||
return Part.makeCircle(radius,center)
|
||||
except:
|
||||
print "couldn't make a circle out of this edge"
|
||||
|
||||
# Fillet code graciously donated by Jacques-Antoine Gaudin
|
||||
|
||||
def fillet(lEdges,r):
|
||||
''' Take a list of two Edges & a float as argument,
|
||||
Returns a list of sorted edges describing a round corner'''
|
||||
|
||||
def getCurveType(edge,existingCurveType = None):
|
||||
'''Builds or completes a dictionnary containing edges with keys "Arc" and "Line"'''
|
||||
if not existingCurveType :
|
||||
existingCurveType = { 'Line' : [], 'Arc' : [] }
|
||||
if issubclass(type(edge.Curve),Part.Line) :
|
||||
existingCurveType['Line'] += [edge]
|
||||
elif issubclass(type(edge.Curve),Part.Circle) :
|
||||
existingCurveType['Arc'] += [edge]
|
||||
else :
|
||||
raise Exception("Edge's curve must be either Line or Arc")
|
||||
return existingCurveType
|
||||
|
||||
rndEdges = lEdges[0:2]
|
||||
rndEdges = sortEdges(rndEdges)
|
||||
|
||||
if len(rndEdges) < 2 :
|
||||
return rndEdges
|
||||
|
||||
if r <= 0 :
|
||||
print "fcgeo.fillet : Error : radius is negative."
|
||||
return rndEdges
|
||||
|
||||
curveType = getCurveType(rndEdges[0])
|
||||
curveType = getCurveType(rndEdges[1],curveType)
|
||||
|
||||
lVertexes = rndEdges[0].Vertexes + [rndEdges[1].Vertexes[-1]]
|
||||
|
||||
if len(curveType['Line']) == 2:
|
||||
|
||||
# Deals with 2-line-edges lists --------------------------------------
|
||||
|
||||
U1 = lVertexes[0].Point.sub(lVertexes[1].Point) ; U1.normalize()
|
||||
U2 = lVertexes[2].Point.sub(lVertexes[1].Point) ; U2.normalize()
|
||||
alpha = U1.getAngle(U2)
|
||||
|
||||
if round(alpha,precision) == 0 or round(alpha - math.pi,precision) == 0: # Edges have same direction
|
||||
print "fcgeo.fillet : Warning : edges have same direction. Did nothing"
|
||||
return rndEdges
|
||||
|
||||
dToCenter = r / math.sin(alpha/2.)
|
||||
dToTangent = (dToCenter**2-r**2)**(0.5)
|
||||
dirVect = Vector(U1) ; dirVect.scale(dToTangent,dToTangent,dToTangent)
|
||||
arcPt1 = lVertexes[1].Point.add(dirVect)
|
||||
|
||||
dirVect = U2.add(U1) ; dirVect.normalize()
|
||||
dirVect.scale(dToCenter-r,dToCenter-r,dToCenter-r)
|
||||
arcPt2 = lVertexes[1].Point.add(dirVect)
|
||||
|
||||
dirVect = Vector(U2) ; dirVect.scale(dToTangent,dToTangent,dToTangent)
|
||||
arcPt3 = lVertexes[1].Point.add(dirVect)
|
||||
|
||||
if (dToTangent>lEdges[0].Length) or (dToTangent>lEdges[1].Length) :
|
||||
print "fcgeo.fillet : Error : radius value ", r," is too high"
|
||||
return rndEdges
|
||||
|
||||
rndEdges[1] = Part.Edge(Part.Arc(arcPt1,arcPt2,arcPt3))
|
||||
rndEdges[0] = Part.Edge(Part.Line(lVertexes[0].Point,arcPt1))
|
||||
rndEdges += [Part.Edge(Part.Line(arcPt3,lVertexes[2].Point))]
|
||||
|
||||
return rndEdges
|
||||
|
||||
elif len(curveType['Arc']) == 1 :
|
||||
|
||||
# Deals with lists containing an arc and a line ----------------------------------
|
||||
|
||||
if lEdges[0] in curveType['Arc'] :
|
||||
lineEnd = lVertexes[2] ; arcEnd = lVertexes[0] ; arcFirst = True
|
||||
else :
|
||||
lineEnd = lVertexes[0] ; arcEnd = lVertexes[2] ; arcFirst = False
|
||||
arcCenter = curveType['Arc'][0].Curve.Center
|
||||
arcRadius = curveType['Arc'][0].Curve.Radius
|
||||
arcAxis = curveType['Arc'][0].Curve.Axis
|
||||
arcLength = curveType['Arc'][0].Length
|
||||
|
||||
U1 = lineEnd.Point.sub(lVertexes[1].Point) ; U1.normalize()
|
||||
toCenter = arcCenter.sub(lVertexes[1].Point)
|
||||
if arcFirst : # make sure the tangent points towards the arc
|
||||
T = arcAxis.cross(toCenter)
|
||||
else :
|
||||
T = toCenter.cross(arcAxis)
|
||||
|
||||
projCenter = toCenter.dot(U1)
|
||||
if round(abs(projCenter),precision) > 0 :
|
||||
normToLine = U1.cross(T).cross(U1)
|
||||
else :
|
||||
normToLine = Vector(toCenter)
|
||||
normToLine.normalize()
|
||||
|
||||
dCenterToLine = toCenter.dot(normToLine) - r
|
||||
|
||||
if round(projCenter,precision) > 0 :
|
||||
newRadius = arcRadius - r
|
||||
elif round(projCenter,precision) < 0 or (round(projCenter,precision) == 0 and U1.dot(T) > 0):
|
||||
newRadius = arcRadius + r
|
||||
else :
|
||||
print "fcgeo.fillet : Warning : edges are already tangent. Did nothing"
|
||||
return rndEdges
|
||||
|
||||
toNewCent = newRadius**2-dCenterToLine**2
|
||||
if toNewCent > 0 :
|
||||
toNewCent = abs(abs(projCenter) - toNewCent**(0.5))
|
||||
else :
|
||||
print "fcgeo.fillet : Error : radius value ", r," is too high"
|
||||
return rndEdges
|
||||
|
||||
U1.scale(toNewCent,toNewCent,toNewCent)
|
||||
normToLine.scale(r,r,r)
|
||||
newCent = lVertexes[1].Point.add(U1).add(normToLine)
|
||||
|
||||
arcPt1= lVertexes[1].Point.add(U1)
|
||||
arcPt2= lVertexes[1].Point.sub(newCent); arcPt2.normalize()
|
||||
arcPt2.scale(r,r,r) ; arcPt2 = arcPt2.add(newCent)
|
||||
if newRadius == arcRadius - r :
|
||||
arcPt3= newCent.sub(arcCenter)
|
||||
else :
|
||||
arcPt3= arcCenter.sub(newCent)
|
||||
arcPt3.normalize()
|
||||
arcPt3.scale(r,r,r) ; arcPt3 = arcPt3.add(newCent)
|
||||
arcPt = [arcPt1,arcPt2,arcPt3]
|
||||
|
||||
|
||||
# Warning : In the following I used a trick for calling the right element
|
||||
# in arcPt or V : arcFirst is a boolean so - not arcFirst is -0 or -1
|
||||
# list[-1] is the last element of a list and list[0] the first
|
||||
# this way I don't have to proceed tests to know the position of the arc
|
||||
|
||||
myTrick = not arcFirst
|
||||
|
||||
V = [arcPt3]
|
||||
V += [arcEnd.Point]
|
||||
|
||||
toCenter.scale(-1,-1,-1)
|
||||
|
||||
delLength = arcRadius * V[0].sub(arcCenter).getAngle(toCenter)
|
||||
if delLength > arcLength or toNewCent > curveType['Line'][0].Length:
|
||||
print "fcgeo.fillet : Error : radius value ", r," is too high"
|
||||
return rndEdges
|
||||
|
||||
arcAsEdge = arcFrom2Pts(V[-arcFirst],V[-myTrick],arcCenter,arcAxis)
|
||||
|
||||
V = [lineEnd.Point,arcPt1]
|
||||
lineAsEdge = Part.Edge(Part.Line(V[-arcFirst],V[myTrick]))
|
||||
|
||||
rndEdges[not arcFirst] = arcAsEdge
|
||||
rndEdges[arcFirst] = lineAsEdge
|
||||
rndEdges[1:1] = [Part.Edge(Part.Arc(arcPt[- arcFirst],arcPt[1],arcPt[- myTrick]))]
|
||||
|
||||
return rndEdges
|
||||
|
||||
elif len(curveType['Arc']) == 2 :
|
||||
|
||||
# Deals with lists of 2 arc-edges --------------------------------------------
|
||||
|
||||
arcCenter, arcRadius, arcAxis, arcLength, toCenter, T, newRadius = [], [], [], [], [], [], []
|
||||
for i in range(2) :
|
||||
arcCenter += [curveType['Arc'][i].Curve.Center]
|
||||
arcRadius += [curveType['Arc'][i].Curve.Radius]
|
||||
arcAxis += [curveType['Arc'][i].Curve.Axis]
|
||||
arcLength += [curveType['Arc'][i].Length]
|
||||
toCenter += [arcCenter[i].sub(lVertexes[1].Point)]
|
||||
T += [arcAxis[0].cross(toCenter[0])]
|
||||
T += [toCenter[1].cross(arcAxis[1])]
|
||||
CentToCent = toCenter[1].sub(toCenter[0])
|
||||
dCentToCent = CentToCent.Length
|
||||
|
||||
sameDirection = (arcAxis[0].dot(arcAxis[1]) > 0)
|
||||
TcrossT = T[0].cross(T[1])
|
||||
if sameDirection :
|
||||
if round(TcrossT.dot(arcAxis[0]),precision) > 0 :
|
||||
newRadius += [arcRadius[0]+r]
|
||||
newRadius += [arcRadius[1]+r]
|
||||
elif round(TcrossT.dot(arcAxis[0]),precision) < 0 :
|
||||
newRadius += [arcRadius[0]-r]
|
||||
newRadius += [arcRadius[1]-r]
|
||||
elif T[0].dot(T[1]) > 0 :
|
||||
newRadius += [arcRadius[0]+r]
|
||||
newRadius += [arcRadius[1]+r]
|
||||
else :
|
||||
print "fcgeo.fillet : Warning : edges are already tangent. Did nothing"
|
||||
return rndEdges
|
||||
elif not sameDirection :
|
||||
if round(TcrossT.dot(arcAxis[0]),precision) > 0 :
|
||||
newRadius += [arcRadius[0]+r]
|
||||
newRadius += [arcRadius[1]-r]
|
||||
elif round(TcrossT.dot(arcAxis[0]),precision) < 0 :
|
||||
newRadius += [arcRadius[0]-r]
|
||||
newRadius += [arcRadius[1]+r]
|
||||
elif T[0].dot(T[1]) > 0 :
|
||||
if arcRadius[0] > arcRadius[1] :
|
||||
newRadius += [arcRadius[0]-r]
|
||||
newRadius += [arcRadius[1]+r]
|
||||
elif arcRadius[1] > arcRadius[0] :
|
||||
newRadius += [arcRadius[0]+r]
|
||||
newRadius += [arcRadius[1]-r]
|
||||
else :
|
||||
print "fcgeo.fillet : Warning : arcs are coincident. Did nothing"
|
||||
return rndEdges
|
||||
else :
|
||||
print "fcgeo.fillet : Warning : edges are already tangent. Did nothing"
|
||||
return rndEdges
|
||||
|
||||
if newRadius[0]+newRadius[1] < dCentToCent or \
|
||||
newRadius[0]-newRadius[1] > dCentToCent or \
|
||||
newRadius[1]-newRadius[0] > dCentToCent :
|
||||
print "fcgeo.fillet : Error : radius value ", r," is too high"
|
||||
return rndEdges
|
||||
|
||||
x = (dCentToCent**2+newRadius[0]**2-newRadius[1]**2)/(2*dCentToCent)
|
||||
y = (newRadius[0]**2-x**2)**(0.5)
|
||||
|
||||
CentToCent.normalize() ; toCenter[0].normalize() ; toCenter[1].normalize()
|
||||
if abs(toCenter[0].dot(toCenter[1])) != 1 :
|
||||
normVect = CentToCent.cross(CentToCent.cross(toCenter[0]))
|
||||
else :
|
||||
normVect = T[0]
|
||||
normVect.normalize()
|
||||
CentToCent.scale(x,x,x) ; normVect.scale(y,y,y)
|
||||
newCent = arcCenter[0].add(CentToCent.add(normVect))
|
||||
CentToNewCent = [newCent.sub(arcCenter[0]),newCent.sub(arcCenter[1])]
|
||||
for i in range(2) :
|
||||
CentToNewCent[i].normalize()
|
||||
if newRadius[i] == arcRadius[i]+r :
|
||||
CentToNewCent[i].scale(-r,-r,-r)
|
||||
else :
|
||||
CentToNewCent[i].scale(r,r,r)
|
||||
toThirdPt = lVertexes[1].Point.sub(newCent) ; toThirdPt.normalize()
|
||||
toThirdPt.scale(r,r,r)
|
||||
arcPt1 = newCent.add(CentToNewCent[0])
|
||||
arcPt2 = newCent.add(toThirdPt)
|
||||
arcPt3 = newCent.add(CentToNewCent[1])
|
||||
arcPt = [arcPt1,arcPt2,arcPt3]
|
||||
|
||||
arcAsEdge = []
|
||||
for i in range(2) :
|
||||
toCenter[i].scale(-1,-1,-1)
|
||||
delLength = arcRadius[i] * arcPt[-i].sub(arcCenter[i]).getAngle(toCenter[i])
|
||||
if delLength > arcLength[i] :
|
||||
print "fcgeo.fillet : Error : radius value ", r," is too high"
|
||||
return rndEdges
|
||||
V = [arcPt[-i],lVertexes[-i].Point]
|
||||
arcAsEdge += [arcFrom2Pts(V[i-1],V[-i],arcCenter[i],arcAxis[i])]
|
||||
|
||||
rndEdges[0] = arcAsEdge[0]
|
||||
rndEdges[1] = arcAsEdge[1]
|
||||
rndEdges[1:1] = [Part.Edge(Part.Arc(arcPt[0],arcPt[1],arcPt[2]))]
|
||||
|
||||
return rndEdges
|
||||
|
||||
def filletWire(aWire,r,makeClosed=True):
|
||||
''' Fillets each angle of a wire with r as radius value'''
|
||||
|
||||
edges = aWire.Edges
|
||||
edges = sortEdges(edges)
|
||||
filEdges = [edges[0]]
|
||||
for i in range(len(edges)-1):
|
||||
result = fillet([filEdges[-1],edges[i+1]],r)
|
||||
if len(result)>2:
|
||||
filEdges[-1:] = result[0:3]
|
||||
else :
|
||||
filEdges[-1:] = result[0:2]
|
||||
if isReallyClosed(aWire) and makeClosed :
|
||||
result = fillet([filEdges[-1],filEdges[0]],r)
|
||||
if len(result)>2:
|
||||
filEdges[-1:] = result[0:2]
|
||||
filEdges[0] = result[2]
|
||||
return Part.Wire(filEdges)
|
||||
|
||||
|
||||
# circle functions *********************************************************
|
||||
|
||||
|
|
|
@ -28,12 +28,15 @@ __url__ = ["http://free-cad.sourceforge.net"]
|
|||
'''
|
||||
This script imports SVG files in FreeCAD. Currently only reads the following entities:
|
||||
paths, lines, circular arcs ,rects, circles, ellipses, polygons, polylines.
|
||||
currently unsupported: image, rounded rect(rx,ry), elliptical arcs
|
||||
currently unsupported: use, image
|
||||
'''
|
||||
#ToDo:
|
||||
# elliptical arc segments
|
||||
# rounded rects (elliptical arcs)
|
||||
# ignoring CDATA
|
||||
# handle image element (external references and inline base64)
|
||||
# debug Problem with 'Sans' font from Inkscape
|
||||
# debug Problem with fill color
|
||||
# implement inherting fill style from group
|
||||
# handle viewbox and units
|
||||
|
||||
import xml.sax, string, FreeCAD, os, math, re, Draft
|
||||
from draftlibs import fcvec
|
||||
|
@ -48,154 +51,154 @@ except: draftui = None
|
|||
pythonopen = open
|
||||
|
||||
svgcolors = {
|
||||
'Pink': [255, 192, 203],
|
||||
'Blue': [0, 0, 255],
|
||||
'Honeydew': [240, 255, 240],
|
||||
'Purple': [128, 0, 128],
|
||||
'Fuchsia': [255, 0, 255],
|
||||
'LawnGreen': [124, 252, 0],
|
||||
'Amethyst': [153, 102, 204],
|
||||
'Crimson': [220, 20, 60],
|
||||
'White': [255, 255, 255],
|
||||
'NavajoWhite': [255, 222, 173],
|
||||
'Cornsilk': [255, 248, 220],
|
||||
'Bisque': [255, 228, 196],
|
||||
'PaleGreen': [152, 251, 152],
|
||||
'Brown': [165, 42, 42],
|
||||
'DarkTurquoise': [0, 206, 209],
|
||||
'DarkGreen': [0, 100, 0],
|
||||
'MediumOrchid': [186, 85, 211],
|
||||
'Chocolate': [210, 105, 30],
|
||||
'PapayaWhip': [255, 239, 213],
|
||||
'Olive': [128, 128, 0],
|
||||
'Silver': [192, 192, 192],
|
||||
'PeachPuff': [255, 218, 185],
|
||||
'Plum': [221, 160, 221],
|
||||
'DarkGoldenrod': [184, 134, 11],
|
||||
'SlateGrey': [112, 128, 144],
|
||||
'MintCream': [245, 255, 250],
|
||||
'CornflowerBlue': [100, 149, 237],
|
||||
'Gold': [255, 215, 0],
|
||||
'HotPink': [255, 105, 180],
|
||||
'DarkBlue': [0, 0, 139],
|
||||
'LimeGreen': [50, 205, 50],
|
||||
'DeepSkyBlue': [0, 191, 255],
|
||||
'DarkKhaki': [189, 183, 107],
|
||||
'LightGrey': [211, 211, 211],
|
||||
'Yellow': [255, 255, 0],
|
||||
'Gainsboro': [220, 220, 220],
|
||||
'MistyRose': [255, 228, 225],
|
||||
'SandyBrown': [244, 164, 96],
|
||||
'DeepPink': [255, 20, 147],
|
||||
'Magenta': [255, 0, 255],
|
||||
'AliceBlue': [240, 248, 255],
|
||||
'DarkCyan': [0, 139, 139],
|
||||
'DarkSlateGrey': [47, 79, 79],
|
||||
'GreenYellow': [173, 255, 47],
|
||||
'DarkOrchid': [153, 50, 204],
|
||||
'OliveDrab': [107, 142, 35],
|
||||
'Chartreuse': [127, 255, 0],
|
||||
'Peru': [205, 133, 63],
|
||||
'Orange': [255, 165, 0],
|
||||
'Red': [255, 0, 0],
|
||||
'Wheat': [245, 222, 179],
|
||||
'LightCyan': [224, 255, 255],
|
||||
'LightSeaGreen': [32, 178, 170],
|
||||
'BlueViolet': [138, 43, 226],
|
||||
'LightSlateGrey': [119, 136, 153],
|
||||
'Cyan': [0, 255, 255],
|
||||
'MediumPurple': [147, 112, 219],
|
||||
'MidnightBlue': [25, 25, 112],
|
||||
'FireBrick': [178, 34, 34],
|
||||
'PaleTurquoise': [175, 238, 238],
|
||||
'PaleGoldenrod': [238, 232, 170],
|
||||
'Gray': [128, 128, 128],
|
||||
'MediumSeaGreen': [60, 179, 113],
|
||||
'Moccasin': [255, 228, 181],
|
||||
'Ivory': [255, 255, 240],
|
||||
'DarkSlateBlue': [72, 61, 139],
|
||||
'Beige': [245, 245, 220],
|
||||
'Green': [0, 128, 0],
|
||||
'SlateBlue': [106, 90, 205],
|
||||
'Teal': [0, 128, 128],
|
||||
'Azure': [240, 255, 255],
|
||||
'LightSteelBlue': [176, 196, 222],
|
||||
'DimGrey': [105, 105, 105],
|
||||
'Tan': [210, 180, 140],
|
||||
'AntiqueWhite': [250, 235, 215],
|
||||
'SkyBlue': [135, 206, 235],
|
||||
'GhostWhite': [248, 248, 255],
|
||||
'MediumTurquoise': [72, 209, 204],
|
||||
'FloralWhite': [255, 250, 240],
|
||||
'LavenderBlush': [255, 240, 245],
|
||||
'SeaGreen': [46, 139, 87],
|
||||
'Lavender': [230, 230, 250],
|
||||
'BlanchedAlmond': [255, 235, 205],
|
||||
'DarkOliveGreen': [85, 107, 47],
|
||||
'DarkSeaGreen': [143, 188, 143],
|
||||
'SpringGreen': [0, 255, 127],
|
||||
'Navy': [0, 0, 128],
|
||||
'Orchid': [218, 112, 214],
|
||||
'SaddleBrown': [139, 69, 19],
|
||||
'IndianRed': [205, 92, 92],
|
||||
'Snow': [255, 250, 250],
|
||||
'SteelBlue': [70, 130, 180],
|
||||
'MediumSlateBlue': [123, 104, 238],
|
||||
'Black': [0, 0, 0],
|
||||
'LightBlue': [173, 216, 230],
|
||||
'Turquoise': [64, 224, 208],
|
||||
'MediumVioletRed': [199, 21, 133],
|
||||
'DarkViolet': [148, 0, 211],
|
||||
'DarkGray': [169, 169, 169],
|
||||
'Salmon': [250, 128, 114],
|
||||
'DarkMagenta': [139, 0, 139],
|
||||
'Tomato': [255, 99, 71],
|
||||
'WhiteSmoke': [245, 245, 245],
|
||||
'Goldenrod': [218, 165, 32],
|
||||
'MediumSpringGreen': [0, 250, 154],
|
||||
'DodgerBlue': [30, 144, 255],
|
||||
'Aqua': [0, 255, 255],
|
||||
'ForestGreen': [34, 139, 34],
|
||||
'LemonChiffon': [255, 250, 205],
|
||||
'LightSlateGray': [119, 136, 153],
|
||||
'SlateGray': [112, 128, 144],
|
||||
'LightGray': [211, 211, 211],
|
||||
'Indigo': [75, 0, 130],
|
||||
'CadetBlue': [95, 158, 160],
|
||||
'LightYellow': [255, 255, 224],
|
||||
'DarkOrange': [255, 140, 0],
|
||||
'PowderBlue': [176, 224, 230],
|
||||
'RoyalBlue': [65, 105, 225],
|
||||
'Sienna': [160, 82, 45],
|
||||
'Thistle': [216, 191, 216],
|
||||
'Lime': [0, 255, 0],
|
||||
'Seashell': [255, 245, 238],
|
||||
'DarkRed': [139, 0, 0],
|
||||
'LightSkyBlue': [135, 206, 250],
|
||||
'YellowGreen': [154, 205, 50],
|
||||
'Aquamarine': [127, 255, 212],
|
||||
'LightCoral': [240, 128, 128],
|
||||
'DarkSlateGray': [47, 79, 79],
|
||||
'Khaki': [240, 230, 140],
|
||||
'DarkGrey': [169, 169, 169],
|
||||
'BurlyWood': [222, 184, 135],
|
||||
'LightGoldenrodYellow': [250, 250, 210],
|
||||
'MediumBlue': [0, 0, 205],
|
||||
'DarkSalmon': [233, 150, 122],
|
||||
'RosyBrown': [188, 143, 143],
|
||||
'LightSalmon': [255, 160, 122],
|
||||
'PaleVioletRed': [219, 112, 147],
|
||||
'Coral': [255, 127, 80],
|
||||
'Violet': [238, 130, 238],
|
||||
'Grey': [128, 128, 128],
|
||||
'LightGreen': [144, 238, 144],
|
||||
'Linen': [250, 240, 230],
|
||||
'OrangeRed': [255, 69, 0],
|
||||
'DimGray': [105, 105, 105],
|
||||
'Maroon': [128, 0, 0],
|
||||
'LightPink': [255, 182, 193],
|
||||
'MediumAquamarine': [102, 205, 170],
|
||||
'OldLace': [253, 245, 230]
|
||||
'Pink': (255, 192, 203),
|
||||
'Blue': (0, 0, 255),
|
||||
'Honeydew': (240, 255, 240),
|
||||
'Purple': (128, 0, 128),
|
||||
'Fuchsia': (255, 0, 255),
|
||||
'LawnGreen': (124, 252, 0),
|
||||
'Amethyst': (153, 102, 204),
|
||||
'Crimson': (220, 20, 60),
|
||||
'White': (255, 255, 255),
|
||||
'NavajoWhite': (255, 222, 173),
|
||||
'Cornsilk': (255, 248, 220),
|
||||
'Bisque': (255, 228, 196),
|
||||
'PaleGreen': (152, 251, 152),
|
||||
'Brown': (165, 42, 42),
|
||||
'DarkTurquoise': (0, 206, 209),
|
||||
'DarkGreen': (0, 100, 0),
|
||||
'MediumOrchid': (186, 85, 211),
|
||||
'Chocolate': (210, 105, 30),
|
||||
'PapayaWhip': (255, 239, 213),
|
||||
'Olive': (128, 128, 0),
|
||||
'Silver': (192, 192, 192),
|
||||
'PeachPuff': (255, 218, 185),
|
||||
'Plum': (221, 160, 221),
|
||||
'DarkGoldenrod': (184, 134, 11),
|
||||
'SlateGrey': (112, 128, 144),
|
||||
'MintCream': (245, 255, 250),
|
||||
'CornflowerBlue': (100, 149, 237),
|
||||
'Gold': (255, 215, 0),
|
||||
'HotPink': (255, 105, 180),
|
||||
'DarkBlue': (0, 0, 139),
|
||||
'LimeGreen': (50, 205, 50),
|
||||
'DeepSkyBlue': (0, 191, 255),
|
||||
'DarkKhaki': (189, 183, 107),
|
||||
'LightGrey': (211, 211, 211),
|
||||
'Yellow': (255, 255, 0),
|
||||
'Gainsboro': (220, 220, 220),
|
||||
'MistyRose': (255, 228, 225),
|
||||
'SandyBrown': (244, 164, 96),
|
||||
'DeepPink': (255, 20, 147),
|
||||
'Magenta': (255, 0, 255),
|
||||
'AliceBlue': (240, 248, 255),
|
||||
'DarkCyan': (0, 139, 139),
|
||||
'DarkSlateGrey': (47, 79, 79),
|
||||
'GreenYellow': (173, 255, 47),
|
||||
'DarkOrchid': (153, 50, 204),
|
||||
'OliveDrab': (107, 142, 35),
|
||||
'Chartreuse': (127, 255, 0),
|
||||
'Peru': (205, 133, 63),
|
||||
'Orange': (255, 165, 0),
|
||||
'Red': (255, 0, 0),
|
||||
'Wheat': (245, 222, 179),
|
||||
'LightCyan': (224, 255, 255),
|
||||
'LightSeaGreen': (32, 178, 170),
|
||||
'BlueViolet': (138, 43, 226),
|
||||
'LightSlateGrey': (119, 136, 153),
|
||||
'Cyan': (0, 255, 255),
|
||||
'MediumPurple': (147, 112, 219),
|
||||
'MidnightBlue': (25, 25, 112),
|
||||
'FireBrick': (178, 34, 34),
|
||||
'PaleTurquoise': (175, 238, 238),
|
||||
'PaleGoldenrod': (238, 232, 170),
|
||||
'Gray': (128, 128, 128),
|
||||
'MediumSeaGreen': (60, 179, 113),
|
||||
'Moccasin': (255, 228, 181),
|
||||
'Ivory': (255, 255, 240),
|
||||
'DarkSlateBlue': (72, 61, 139),
|
||||
'Beige': (245, 245, 220),
|
||||
'Green': (0, 128, 0),
|
||||
'SlateBlue': (106, 90, 205),
|
||||
'Teal': (0, 128, 128),
|
||||
'Azure': (240, 255, 255),
|
||||
'LightSteelBlue': (176, 196, 222),
|
||||
'DimGrey': (105, 105, 105),
|
||||
'Tan': (210, 180, 140),
|
||||
'AntiqueWhite': (250, 235, 215),
|
||||
'SkyBlue': (135, 206, 235),
|
||||
'GhostWhite': (248, 248, 255),
|
||||
'MediumTurquoise': (72, 209, 204),
|
||||
'FloralWhite': (255, 250, 240),
|
||||
'LavenderBlush': (255, 240, 245),
|
||||
'SeaGreen': (46, 139, 87),
|
||||
'Lavender': (230, 230, 250),
|
||||
'BlanchedAlmond': (255, 235, 205),
|
||||
'DarkOliveGreen': (85, 107, 47),
|
||||
'DarkSeaGreen': (143, 188, 143),
|
||||
'SpringGreen': (0, 255, 127),
|
||||
'Navy': (0, 0, 128),
|
||||
'Orchid': (218, 112, 214),
|
||||
'SaddleBrown': (139, 69, 19),
|
||||
'IndianRed': (205, 92, 92),
|
||||
'Snow': (255, 250, 250),
|
||||
'SteelBlue': (70, 130, 180),
|
||||
'MediumSlateBlue': (123, 104, 238),
|
||||
'Black': (0, 0, 0),
|
||||
'LightBlue': (173, 216, 230),
|
||||
'Turquoise': (64, 224, 208),
|
||||
'MediumVioletRed': (199, 21, 133),
|
||||
'DarkViolet': (148, 0, 211),
|
||||
'DarkGray': (169, 169, 169),
|
||||
'Salmon': (250, 128, 114),
|
||||
'DarkMagenta': (139, 0, 139),
|
||||
'Tomato': (255, 99, 71),
|
||||
'WhiteSmoke': (245, 245, 245),
|
||||
'Goldenrod': (218, 165, 32),
|
||||
'MediumSpringGreen': (0, 250, 154),
|
||||
'DodgerBlue': (30, 144, 255),
|
||||
'Aqua': (0, 255, 255),
|
||||
'ForestGreen': (34, 139, 34),
|
||||
'LemonChiffon': (255, 250, 205),
|
||||
'LightSlateGray': (119, 136, 153),
|
||||
'SlateGray': (112, 128, 144),
|
||||
'LightGray': (211, 211, 211),
|
||||
'Indigo': (75, 0, 130),
|
||||
'CadetBlue': (95, 158, 160),
|
||||
'LightYellow': (255, 255, 224),
|
||||
'DarkOrange': (255, 140, 0),
|
||||
'PowderBlue': (176, 224, 230),
|
||||
'RoyalBlue': (65, 105, 225),
|
||||
'Sienna': (160, 82, 45),
|
||||
'Thistle': (216, 191, 216),
|
||||
'Lime': (0, 255, 0),
|
||||
'Seashell': (255, 245, 238),
|
||||
'DarkRed': (139, 0, 0),
|
||||
'LightSkyBlue': (135, 206, 250),
|
||||
'YellowGreen': (154, 205, 50),
|
||||
'Aquamarine': (127, 255, 212),
|
||||
'LightCoral': (240, 128, 128),
|
||||
'DarkSlateGray': (47, 79, 79),
|
||||
'Khaki': (240, 230, 140),
|
||||
'DarkGrey': (169, 169, 169),
|
||||
'BurlyWood': (222, 184, 135),
|
||||
'LightGoldenrodYellow': (250, 250, 210),
|
||||
'MediumBlue': (0, 0, 205),
|
||||
'DarkSalmon': (233, 150, 122),
|
||||
'RosyBrown': (188, 143, 143),
|
||||
'LightSalmon': (255, 160, 122),
|
||||
'PaleVioletRed': (219, 112, 147),
|
||||
'Coral': (255, 127, 80),
|
||||
'Violet': (238, 130, 238),
|
||||
'Grey': (128, 128, 128),
|
||||
'LightGreen': (144, 238, 144),
|
||||
'Linen': (250, 240, 230),
|
||||
'OrangeRed': (255, 69, 0),
|
||||
'DimGray': (105, 105, 105),
|
||||
'Maroon': (128, 0, 0),
|
||||
'LightPink': (255, 182, 193),
|
||||
'MediumAquamarine': (102, 205, 170),
|
||||
'OldLace': (253, 245, 230)
|
||||
}
|
||||
|
||||
def getcolor(color):
|
||||
|
@ -227,6 +230,85 @@ def getsize(width):
|
|||
except ValueError:
|
||||
return width
|
||||
|
||||
def makewire(path,checkclosed=False,donttry=False):
|
||||
'''try to make a wire out of the list of edges. If the 'Wire' functions fails or the wire is not
|
||||
closed if required the 'connectEdgesToWires' function is used'''
|
||||
#ToDo Do not catch all exceptions
|
||||
if not donttry:
|
||||
try:
|
||||
sh = Part.Wire(path)
|
||||
isok = (not checkclosed) or sh.isClosed()
|
||||
except:# BRep_API:command not done
|
||||
isok = False
|
||||
if donttry or not isok:
|
||||
#Code from wmayer forum p15549 to fix the tolerance problem
|
||||
#original tolerance = 0.00001
|
||||
comp=Part.Compound(path)
|
||||
sh = comp.connectEdgesToWires(False,10**(-1*(Draft.precision()-2))).Wires[0]
|
||||
return sh
|
||||
|
||||
def arccenter2end(center,rx,ry,angle1,angledelta,xrotation=0.0):
|
||||
'''calculate start and end vector and flags of an arc given in center parametrization
|
||||
see http://www.w3.org/TR/SVG/implnote.html#ArcImplementationNotes
|
||||
returns (v1,v2,largerc,sweep)'''
|
||||
vr1=Vector(rx*math.cos(angle1),ry*math.sin(angle1),0)
|
||||
vr2=Vector(rx*math.cos(angle1+angledelta),ry*math.sin(angle1+angledelta),0)
|
||||
mxrot=FreeCAD.Matrix()
|
||||
mxrot.rotateZ(xrotation)
|
||||
v1 = mxrot.multiply(vr1).add(center)
|
||||
v2 = mxrot.multiply(vr2).add(center)
|
||||
fa = ((abs(angledelta) / math.pi) % 2) > 1 # <180deg
|
||||
fs = angledelta < 0
|
||||
return v1,v2,fa,fs
|
||||
|
||||
def arcend2center(lastvec,currentvec,rx,ry,xrotation=0.0,correction=False):
|
||||
'''calculate (positive and negative) possible centers for an arc in endpoint parameterization
|
||||
see http://www.w3.org/TR/SVG/implnote.html#ArcImplementationNotes
|
||||
rotation or x-axis has to be specified in radians (CCW)
|
||||
the sweepflag is interpreted as: sweepflag <==> arc is travelled clockwise
|
||||
returns [(vcenter+,angle1+,angledelta+),(...-)]'''
|
||||
#scalefacsign = 1 if (largeflag != sweepflag) else -1
|
||||
rx = float(rx)
|
||||
ry = float(ry)
|
||||
v0 = lastvec.sub(currentvec)
|
||||
v0 = v0.multiply(0.5)
|
||||
m1=FreeCAD.Matrix()
|
||||
m1.rotateZ(-xrotation) #Formular 6.5.1
|
||||
v1=m1.multiply(v0)
|
||||
if correction:
|
||||
eparam = v1.x**2 / rx**2 + v1.y**2 / ry**2
|
||||
if eparam > 1:
|
||||
eproot = math.sqrt(eparam)
|
||||
rx = eproot * rx
|
||||
ry = eproot * ry
|
||||
denom = rx**2 * v1.y**2+ ry**2 * v1.x**2
|
||||
numer = rx**2 * ry**2 -denom
|
||||
results=[]
|
||||
if abs(numer/denom) < 10**(-1*(Draft.precision())):
|
||||
scalefacpos = 0
|
||||
else:
|
||||
try:
|
||||
scalefacpos = math.sqrt(numer/denom)
|
||||
except ValueError:
|
||||
print 'sqrt(%f/%f)' % (numer,denom)
|
||||
scalefacpos = 0
|
||||
for scalefacsign in (1,-1):
|
||||
scalefac = scalefacpos * scalefacsign
|
||||
vcx1 = Vector(v1.y*rx/ry,-v1.x*ry/rx,0).multiply(scalefac) # Step2 F.6.5.2
|
||||
m2=FreeCAD.Matrix()
|
||||
m2.rotateZ(xrotation)
|
||||
centeroff = currentvec.add(lastvec)
|
||||
centeroff = fcvec.scale(centeroff,.5)
|
||||
vcenter = m2.multiply(vcx1).add(centeroff) # Step3 F.6.5.3
|
||||
#angle1 = Vector(1,0,0).getAngle(Vector((v1.x-vcx1.x)/rx,(v1.y-vcx1.y)/ry,0)) # F.6.5.5
|
||||
#angledelta = Vector((v1.x-vcx1.x)/rx,(v1.y-vcx1.y)/ry,0).getAngle(Vector((-v1.x-vcx1.x)/rx,(-v1.y-vcx1.y)/ry,0)) # F.6.5.6
|
||||
#we need the right sign for the angle
|
||||
angle1 = fcvec.angle(Vector(1,0,0),Vector((v1.x-vcx1.x)/rx,(v1.y-vcx1.y)/ry,0)) # F.6.5.5
|
||||
angledelta = fcvec.angle(Vector((v1.x-vcx1.x)/rx,(v1.y-vcx1.y)/ry,0),Vector((-v1.x-vcx1.x)/rx,(-v1.y-vcx1.y)/ry,0)) # F.6.5.6
|
||||
results.append((vcenter,angle1,angledelta))
|
||||
return results,(rx,ry)
|
||||
|
||||
|
||||
def getrgb(color):
|
||||
"returns a rgb value #000000 from a freecad color"
|
||||
r = str(hex(int(color[0]*255)))[2:].zfill(2)
|
||||
|
@ -364,203 +446,159 @@ class svgHandler(xml.sax.ContentHandler):
|
|||
obj = Draft.makeDimension(p1,p2,p3)
|
||||
self.applyTrans(obj)
|
||||
self.format(obj)
|
||||
pathdata = []
|
||||
self.lastdim = obj
|
||||
data['d']=[]
|
||||
pathcommandsre=re.compile('\s*?([mMlLhHvVaAcCqQsStTzZ])\s*?([^mMlLhHvVaAcCqQsStTzZ]*)\s*?',re.DOTALL)
|
||||
for d,pointsstr in pathcommandsre.findall(' '.join(data['d'])):
|
||||
#for d in pathdata:
|
||||
if (d == "M"):
|
||||
command = "move"
|
||||
relative = False
|
||||
point = []
|
||||
elif (d == "m"):
|
||||
command = "move"
|
||||
relative = True
|
||||
point = []
|
||||
elif (d == "L"):
|
||||
command = "line"
|
||||
relative = False
|
||||
point = []
|
||||
elif (d == "l"):
|
||||
command = "line"
|
||||
relative = True
|
||||
point = []
|
||||
elif (d == "H"):
|
||||
command = "horizontal"
|
||||
relative = False
|
||||
point = []
|
||||
elif (d == "h"):
|
||||
command = "horizontal"
|
||||
relative = True
|
||||
point = []
|
||||
elif (d == "V"):
|
||||
command = "vertical"
|
||||
relative = False
|
||||
point = []
|
||||
elif (d == "v"):
|
||||
command = "vertical"
|
||||
relative = True
|
||||
point = []
|
||||
elif (d == "A"):
|
||||
command = "arc"
|
||||
relative = False
|
||||
point = []
|
||||
elif (d == "a"):
|
||||
command = "arc"
|
||||
relative = True
|
||||
point = []
|
||||
elif (d == "Z") or (d == "z"):
|
||||
command = "close"
|
||||
point = []
|
||||
elif (d == "C"):
|
||||
command = "cubic"
|
||||
relative = False
|
||||
smooth = False
|
||||
point = []
|
||||
elif (d == "c"):
|
||||
command = "cubic"
|
||||
relative = True
|
||||
smooth = False
|
||||
point = []
|
||||
elif (d == "Q"):
|
||||
command = "quadratic"
|
||||
relative = False
|
||||
smooth = False
|
||||
point = []
|
||||
elif (d == "q"):
|
||||
command = "quadratic"
|
||||
relative = True
|
||||
smooth = False
|
||||
point = []
|
||||
elif (d == "S"):
|
||||
command = "cubic"
|
||||
relative = False
|
||||
smooth = True
|
||||
point = []
|
||||
elif (d == "s"):
|
||||
command = "cubic"
|
||||
relative = True
|
||||
smooth = True
|
||||
point = []
|
||||
elif (d == "T"):
|
||||
command = "quadratic"
|
||||
relative = False
|
||||
smooth = True
|
||||
point = []
|
||||
elif (d == "t"):
|
||||
command = "quadratic"
|
||||
relative = True
|
||||
smooth = True
|
||||
point = []
|
||||
pointlist = pointsstr.replace(',',' ').split()
|
||||
while pointlist:
|
||||
if pointlist:
|
||||
point.append(float(pointlist.pop(0)))
|
||||
print "command: ",command, ' point: ',point
|
||||
|
||||
if (len(point)==2) and (command=="move"):
|
||||
if path:
|
||||
sh = Part.Wire(path)
|
||||
if self.fill: sh = Part.Face(sh)
|
||||
sh = self.applyTrans(sh)
|
||||
obj = self.doc.addObject("Part::Feature",pathname)
|
||||
obj.Shape = sh
|
||||
self.format(obj)
|
||||
path = []
|
||||
if firstvec:
|
||||
lastvec = firstvec #Move relative to last move command not last draw command
|
||||
relative = d.islower()
|
||||
pointlist = [float(str1) for str1 in pointsstr.replace(',',' ').split()]
|
||||
if (d == "M" or d == "m"):
|
||||
x = pointlist.pop(0)
|
||||
y = pointlist.pop(0)
|
||||
if path:
|
||||
#sh = Part.Wire(path)
|
||||
sh = makewire(path)
|
||||
if self.fill: sh = Part.Face(sh)
|
||||
sh = self.applyTrans(sh)
|
||||
obj = self.doc.addObject("Part::Feature",pathname)
|
||||
obj.Shape = sh
|
||||
self.format(obj)
|
||||
path = []
|
||||
#if firstvec:
|
||||
# lastvec = firstvec #Move relative to last move command not last draw command
|
||||
if relative:
|
||||
lastvec = lastvec.add(Vector(x,-y,0))
|
||||
else:
|
||||
lastvec = Vector(x,-y,0)
|
||||
firstvec = lastvec
|
||||
print "move ",lastvec
|
||||
lastpole = None
|
||||
if (d == "L" or d == "l") or \
|
||||
((d == 'm' or d == 'M') and pointlist) :
|
||||
for x,y in zip(pointlist[0::2],pointlist[1::2]):
|
||||
if relative:
|
||||
lastvec = lastvec.add(Vector(point[0],-point[1],0))
|
||||
command="line"
|
||||
currentvec = lastvec.add(Vector(x,-y,0))
|
||||
else:
|
||||
lastvec = Vector(point[0],-point[1],0)
|
||||
firstvec = lastvec
|
||||
print "move ",lastvec
|
||||
command = "line"
|
||||
lastpole = None
|
||||
point = []
|
||||
elif (len(point)==2) and (command=="line"):
|
||||
if relative:
|
||||
currentvec = lastvec.add(Vector(point[0],-point[1],0))
|
||||
else:
|
||||
currentvec = Vector(point[0],-point[1],0)
|
||||
currentvec = Vector(x,-y,0)
|
||||
if not fcvec.equals(lastvec,currentvec):
|
||||
seg = Part.Line(lastvec,currentvec).toShape()
|
||||
print "line ",lastvec,currentvec
|
||||
lastvec = currentvec
|
||||
path.append(seg)
|
||||
lastpole = None
|
||||
point = []
|
||||
elif (len(point)==1) and (command=="horizontal"):
|
||||
elif (d == "H" or d == "h"):
|
||||
for x in pointlist:
|
||||
if relative:
|
||||
currentvec = lastvec.add(Vector(point[0],0,0))
|
||||
currentvec = lastvec.add(Vector(x,0,0))
|
||||
else:
|
||||
lasty = path[-1].y
|
||||
currentvec = Vector(point[0],lasty,0)
|
||||
currentvec = Vector(x,lasty,0)
|
||||
seg = Part.Line(lastvec,currentvec).toShape()
|
||||
lastvec = currentvec
|
||||
lastpole = None
|
||||
path.append(seg)
|
||||
point = []
|
||||
elif (len(point)==1) and (command=="vertical"):
|
||||
elif (d == "V" or d == "v"):
|
||||
for y in pointlist:
|
||||
if relative:
|
||||
currentvec = lastvec.add(Vector(0,-point[0],0))
|
||||
currentvec = lastvec.add(Vector(0,-y,0))
|
||||
else:
|
||||
lastx = path[-1].x
|
||||
currentvec = Vector(lastx,-point[0],0)
|
||||
currentvec = Vector(lastx,-y,0)
|
||||
seg = Part.Line(lastvec,currentvec).toShape()
|
||||
lastvec = currentvec
|
||||
lastpole = None
|
||||
path.append(seg)
|
||||
point = []
|
||||
elif (len(point)==7) and (command=="arc"):
|
||||
elif (d == "A" or d == "a"):
|
||||
for rx,ry,xrotation, largeflag, sweepflag,x,y in \
|
||||
zip(pointlist[0::7],pointlist[1::7],pointlist[2::7],pointlist[3::7],pointlist[4::7],pointlist[5::7],pointlist[6::7]):
|
||||
|
||||
#support for large-arc and x-rotation are missing
|
||||
rx,ry,xrotation, largeflag, sweepflag = point[0:5]
|
||||
if relative:
|
||||
currentvec = lastvec.add(Vector(point[-2],-point[-1],0))
|
||||
currentvec = lastvec.add(Vector(x,-y,0))
|
||||
else:
|
||||
currentvec = Vector(point[-2],-point[-1],0)
|
||||
currentvec = Vector(x,-y,0)
|
||||
chord = currentvec.sub(lastvec)
|
||||
# perp = chord.cross(Vector(0,0,-1))
|
||||
# here is a better way to find the perpendicular
|
||||
if sweepflag == 1:
|
||||
# clockwise
|
||||
perp = fcvec.rotate2D(chord,-math.pi/2)
|
||||
else:
|
||||
# anticlockwise
|
||||
perp = fcvec.rotate2D(chord,math.pi/2)
|
||||
chord = fcvec.scale(chord,.5)
|
||||
if chord.Length > rx: a = 0
|
||||
else: a = math.sqrt(rx**2-chord.Length**2)
|
||||
s = rx - a
|
||||
perp = fcvec.scale(perp,s/perp.Length)
|
||||
midpoint = lastvec.add(chord.add(perp))
|
||||
seg = Part.Arc(lastvec,midpoint,currentvec).toShape()
|
||||
if (not largeflag) and abs(rx-ry) < 10**(-1*Draft.precision()): # small circular arc
|
||||
# perp = chord.cross(Vector(0,0,-1))
|
||||
# here is a better way to find the perpendicular
|
||||
if sweepflag == 1:
|
||||
# clockwise
|
||||
perp = fcvec.rotate2D(chord,-math.pi/2)
|
||||
else:
|
||||
# anticlockwise
|
||||
perp = fcvec.rotate2D(chord,math.pi/2)
|
||||
chord = fcvec.scale(chord,.5)
|
||||
if chord.Length > rx: a = 0
|
||||
else: a = math.sqrt(rx**2-chord.Length**2)
|
||||
s = rx - a
|
||||
perp = fcvec.scale(perp,s/perp.Length)
|
||||
midpoint = lastvec.add(chord.add(perp))
|
||||
seg = Part.Arc(lastvec,midpoint,currentvec).toShape()
|
||||
else:# big arc or elliptical arc
|
||||
solution,(rx,ry) = arcend2center(lastvec,currentvec,rx,ry,math.radians(-xrotation),True)
|
||||
negsol = (largeflag != sweepflag)
|
||||
vcenter,angle1,angledelta = solution[negsol]
|
||||
print angle1
|
||||
print angledelta
|
||||
if ry > rx:
|
||||
rx,ry=ry,rx
|
||||
swapaxis = True
|
||||
else:
|
||||
swapaxis = False
|
||||
print 'Elliptical arc %s rx=%f ry=%f' % (vcenter,rx,ry)
|
||||
e1 = Part.Ellipse(vcenter,rx,ry)
|
||||
if sweepflag:
|
||||
#angledelta=-(-angledelta % (math.pi *2)) # Step4
|
||||
#angledelta=(-angledelta % (math.pi *2)) # Step4
|
||||
angle1 = angle1-angledelta
|
||||
#angle1 = math.pi - angle1
|
||||
|
||||
e1a = Part.Arc(e1,angle1-swapaxis*math.radians(90),\
|
||||
angle1+angledelta-swapaxis*math.radians(90))
|
||||
#e1a = Part.Arc(e1,angle1-0*swapaxis*math.radians(90),angle1+angledelta-0*swapaxis*math.radians(90))
|
||||
if swapaxis or xrotation > 10**(-1*Draft.precision()):
|
||||
m3=FreeCAD.Matrix()
|
||||
m3.move(vcenter)
|
||||
rot90=FreeCAD.Matrix(0,-1,0,0,1,0) #90
|
||||
#swapaxism=FreeCAD.Matrix(0,1,0,0,1,0)
|
||||
if swapaxis:
|
||||
m3=m3.multiply(rot90)
|
||||
m3.rotateZ(math.radians(-xrotation))
|
||||
m3.move(vcenter.multiply(-1))
|
||||
e1a.transform(m3)
|
||||
seg = e1a.toShape()
|
||||
if sweepflag:
|
||||
seg.reverse()
|
||||
#obj = self.doc.addObject("Part::Feature",'DEBUG %s'%pathname) #DEBUG
|
||||
#obj.Shape = seg #DEBUG
|
||||
#seg = Part.Line(lastvec,currentvec).toShape() #DEBUG
|
||||
lastvec = currentvec
|
||||
lastpole = None
|
||||
path.append(seg)
|
||||
point = []
|
||||
elif (command=="cubic") and (((smooth==False) and (len(point)==6)) or (smooth==True and (len(point)==4))) :
|
||||
elif (d == "C" or d == "c") or\
|
||||
(d =="S" or d == "s"):
|
||||
smooth = (d == 'S' or d == 's')
|
||||
if smooth:
|
||||
piter = zip(pointlist[2::4],pointlist[3::4],pointlist[0::4],pointlist[1::4],pointlist[2::4],pointlist[3::4])
|
||||
else:
|
||||
piter = zip(pointlist[0::6],pointlist[1::6],pointlist[2::6],pointlist[3::6],pointlist[4::6],pointlist[5::6])
|
||||
for p1x,p1y,p2x,p2y,x,y in piter:
|
||||
if smooth:
|
||||
if relative:
|
||||
currentvec = lastvec.add(Vector(point[2],-point[3],0))
|
||||
pole2 = lastvec.add(Vector(point[0],-point[1],0))
|
||||
else:
|
||||
currentvec = Vector(point[2],-point[3],0)
|
||||
pole2 = Vector(point[0],-point[1],0)
|
||||
if lastpole is not None and lastpole[0]=='cubic':
|
||||
pole1 = lastvec.sub(lastpole[1]).add(lastvec)
|
||||
else:
|
||||
pole1 = lastvec
|
||||
else: #not smooth
|
||||
else:
|
||||
if relative:
|
||||
currentvec = lastvec.add(Vector(point[4],-point[5],0))
|
||||
pole1 = lastvec.add(Vector(point[0],-point[1],0))
|
||||
pole2 = lastvec.add(Vector(point[2],-point[3],0))
|
||||
pole1 = lastvec.add(Vector(p1x,-p1y,0))
|
||||
else:
|
||||
currentvec = Vector(point[4],-point[5],0)
|
||||
pole1 = Vector(point[0],-point[1],0)
|
||||
pole2 = Vector(point[2],-point[3],0)
|
||||
pole1 = Vector(p1x,-p1y,0)
|
||||
if relative:
|
||||
currentvec = lastvec.add(Vector(x,-y,0))
|
||||
pole2 = lastvec.add(Vector(p2x,-p2y,0))
|
||||
else:
|
||||
currentvec = Vector(x,-y,0)
|
||||
pole2 = Vector(p2x,-p2y,0)
|
||||
|
||||
if not fcvec.equals(currentvec,lastvec):
|
||||
mainv = currentvec.sub(lastvec)
|
||||
|
@ -568,8 +606,8 @@ class svgHandler(xml.sax.ContentHandler):
|
|||
pole2v = currentvec.add(pole2)
|
||||
print "cubic curve data:",mainv.normalize(),pole1v.normalize(),pole2v.normalize()
|
||||
if True and \
|
||||
pole1.distanceToLine(lastvec,currentvec) < 20**(-1*Draft.precision()) and \
|
||||
pole2.distanceToLine(lastvec,currentvec) < 20**(-1*Draft.precision()):
|
||||
pole1.distanceToLine(lastvec,currentvec) < 10**(-1*(2+Draft.precision())) and \
|
||||
pole2.distanceToLine(lastvec,currentvec) < 10**(-1*(2+Draft.precision())):
|
||||
print "straight segment"
|
||||
seg = Part.Line(lastvec,currentvec).toShape()
|
||||
else:
|
||||
|
@ -581,66 +619,63 @@ class svgHandler(xml.sax.ContentHandler):
|
|||
lastvec = currentvec
|
||||
lastpole = ('cubic',pole2)
|
||||
path.append(seg)
|
||||
point = []
|
||||
|
||||
elif (command=="quadratic") and (((smooth==False) and (len(point)==4)) or (smooth==True and (len(point)==2))) :
|
||||
elif (d == "Q" or d == "q") or\
|
||||
(d =="T" or d == "t"):
|
||||
smooth = (d == 'T' or d == 't')
|
||||
if smooth:
|
||||
piter = zip(pointlist[1::2],pointlist[1::2],pointlist[0::2],pointlist[1::2])
|
||||
else:
|
||||
piter = zip(pointlist[0::4],pointlist[1::4],pointlist[2::4],pointlist[3::4])
|
||||
for px,py,x,y in piter:
|
||||
if smooth:
|
||||
if relative:
|
||||
currentvec = lastvec.add(Vector(point[0],-point[1],0))
|
||||
else:
|
||||
currentvec = Vector(point[0],-point[1],0)
|
||||
if lastpole is not None and lastpole[0]=='quadratic':
|
||||
pole1 = lastvec.sub(lastpole[1]).add(lastvec)
|
||||
pole = lastvec.sub(lastpole[1]).add(lastvec)
|
||||
else:
|
||||
pole1 = lastvec
|
||||
else: #not smooth
|
||||
pole = lastvec
|
||||
else:
|
||||
if relative:
|
||||
currentvec = lastvec.add(Vector(point[2],-point[3],0))
|
||||
pole1 = lastvec.add(Vector(point[0],-point[1],0))
|
||||
pole = lastvec.add(Vector(px,-py,0))
|
||||
else:
|
||||
currentvec = Vector(point[2],-point[3],0)
|
||||
pole1 = Vector(point[0],-point[1],0)
|
||||
pole = Vector(px,-py,0)
|
||||
if relative:
|
||||
currentvec = lastvec.add(Vector(x,-y,0))
|
||||
else:
|
||||
currentvec = Vector(x,-y,0)
|
||||
|
||||
if not fcvec.equals(currentvec,lastvec):
|
||||
if True and pole1.distanceToLine(lastvec,currentvec) < 20**(-1*Draft.precision()):
|
||||
if True and \
|
||||
pole.distanceToLine(lastvec,currentvec) < 20**(-1*(2+Draft.precision())):
|
||||
print "straight segment"
|
||||
seg = Part.Line(lastvec,currentvec).toShape()
|
||||
else:
|
||||
print "quadratic bezier segment"
|
||||
b = Part.BezierCurve()
|
||||
b.setPoles([lastvec,pole1,currentvec])
|
||||
b.setPoles([lastvec,pole,currentvec])
|
||||
seg = b.toShape()
|
||||
print "connect ",lastvec,currentvec
|
||||
lastvec = currentvec
|
||||
lastpole = ('quadratic',pole1)
|
||||
lastpole = ('quadratic',pole)
|
||||
path.append(seg)
|
||||
point = []
|
||||
|
||||
#while pointlist or command:
|
||||
else:
|
||||
|
||||
if (command == "close"):
|
||||
if not fcvec.equals(lastvec,firstvec):
|
||||
seg = Part.Line(lastvec,firstvec).toShape()
|
||||
path.append(seg)
|
||||
if path: #the path should be closed by now
|
||||
sh = Part.Wire(path)
|
||||
if not sh.isClosed:
|
||||
#Code from wmayer forum p15549 to fix the tolerance problem
|
||||
comp=Part.Compound(path)
|
||||
sh = comp.connectEdgesToWires(False,10**(-1*Draft.precision())).Wires[0] #original tolerance = 0.00001
|
||||
if self.fill: sh = Part.Face(sh)
|
||||
sh = self.applyTrans(sh)
|
||||
obj = self.doc.addObject("Part::Feature",pathname)
|
||||
obj.Shape = sh
|
||||
self.format(obj)
|
||||
path = []
|
||||
if firstvec:
|
||||
lastvec = firstvec #Move relative to last move command not last draw command
|
||||
elif (d == "Z") or (d == "z"):
|
||||
if not fcvec.equals(lastvec,firstvec):
|
||||
seg = Part.Line(lastvec,firstvec).toShape()
|
||||
path.append(seg)
|
||||
if path: #the path should be closed by now
|
||||
#sh=makewire(path,True)
|
||||
sh=makewire(path,donttry=True)
|
||||
if self.fill: sh = Part.Face(sh)
|
||||
sh = self.applyTrans(sh)
|
||||
obj = self.doc.addObject("Part::Feature",pathname)
|
||||
obj.Shape = sh
|
||||
self.format(obj)
|
||||
path = []
|
||||
if firstvec:
|
||||
lastvec = firstvec #Move relative to recent draw command
|
||||
point = []
|
||||
command = None
|
||||
if path:
|
||||
sh = Part.Wire(path)
|
||||
sh=makewire(path,checkclosed=False)
|
||||
#sh = Part.Wire(path)
|
||||
if self.fill: sh = Part.Face(sh)
|
||||
sh = self.applyTrans(sh)
|
||||
obj = self.doc.addObject("Part::Feature",pathname)
|
||||
|
@ -653,9 +688,9 @@ class svgHandler(xml.sax.ContentHandler):
|
|||
if name == "rect":
|
||||
if not pathname: pathname = 'Rectangle'
|
||||
edges = []
|
||||
# if ('rx' not in data or data['rx'] < 10**(-1*Draft.precision())) and \
|
||||
# ('ry' not in data or data['ry'] < 10**(-1*Draft.precision())): #negative values are invalid
|
||||
if True:
|
||||
if ('rx' not in data or data['rx'] < 10**(-1*Draft.precision())) and \
|
||||
('ry' not in data or data['ry'] < 10**(-1*Draft.precision())): #negative values are invalid
|
||||
# if True:
|
||||
p1 = Vector(data['x'],-data['y'],0)
|
||||
p2 = Vector(data['x']+data['width'],-data['y'],0)
|
||||
p3 = Vector(data['x']+data['width'],-data['y']-data['height'],0)
|
||||
|
@ -665,6 +700,7 @@ class svgHandler(xml.sax.ContentHandler):
|
|||
edges.append(Part.Line(p3,p4).toShape())
|
||||
edges.append(Part.Line(p4,p1).toShape())
|
||||
else: #rounded edges
|
||||
#ToTo: check for ry>rx !!!!
|
||||
rx = data.get('rx')
|
||||
ry = data.get('ry') or rx
|
||||
rx = rx or ry
|
||||
|
@ -672,8 +708,46 @@ class svgHandler(xml.sax.ContentHandler):
|
|||
rx = data['width'] / 2.0
|
||||
if ry > 2 * data['height']:
|
||||
ry = data['height'] / 2.0
|
||||
#TBD
|
||||
# Part.Ellipse(c,rx,ry).toShape() #needs a proxy object
|
||||
if rx > ry:
|
||||
mj = rx
|
||||
mi = ry
|
||||
else:
|
||||
mj = ry
|
||||
mi = rx
|
||||
p1=Vector(data['x']+rx,-data['y']-data['height']+ry,0)
|
||||
e1=Part.Ellipse(p1,mj,mi)
|
||||
p2=Vector(data['x']+data['width']-rx,-data['y']-data['height']+ry,0)
|
||||
e2=Part.Ellipse(p2,mj,mi)
|
||||
p3=Vector(data['x']+data['width']-rx,-data['y']-ry,0)
|
||||
e3=Part.Ellipse(p3,mj,mi)
|
||||
p4=Vector(data['x']+rx,-data['y']-ry,0)
|
||||
e4=Part.Ellipse(p4,mj,mi)
|
||||
if rx > ry:
|
||||
e1a=Part.Arc(e1,math.radians(180),math.radians(270))
|
||||
e2a=Part.Arc(e2,math.radians(270),math.radians(360))
|
||||
e3a=Part.Arc(e3,math.radians(0),math.radians(90))
|
||||
e4a=Part.Arc(e4,math.radians(90),math.radians(180))
|
||||
esh=[e1a.toShape(),e2a.toShape(),e3a.toShape(),e4a.toShape()]
|
||||
else:
|
||||
e1a=Part.Arc(e1,math.radians(90),math.radians(180))
|
||||
e2a=Part.Arc(e2,math.radians(180),math.radians(270))
|
||||
e3a=Part.Arc(e3,math.radians(270),math.radians(360))
|
||||
e4a=Part.Arc(e4,math.radians(0),math.radians(90))
|
||||
rot90=FreeCAD.Matrix(0,-1,0,0,1,0)
|
||||
esh=[]
|
||||
for arc,point in ((e1a,p1),(e2a,p2),(e3a,p3),(e4a,p4)):
|
||||
m1=FreeCAD.Matrix()
|
||||
m1.move(point.multiply(1))
|
||||
m1=m1.multiply(rot90)
|
||||
m1.move(point.multiply(-1))
|
||||
#m1.move(point)
|
||||
arc.transform(m1)
|
||||
esh.append(arc.toShape())
|
||||
for esh1,esh2 in zip(esh[-1:]+esh[:-1],esh):
|
||||
p1,p2 = esh1.Vertexes[-1].Point,esh2.Vertexes[0].Point
|
||||
if not fcvec.equals(p1,p2):
|
||||
edges.append(Part.Line(esh1.Vertexes[-1].Point,esh2.Vertexes[0].Point).toShape()) #straight segments
|
||||
edges.append(esh2) # elliptical segments
|
||||
sh = Part.Wire(edges)
|
||||
if self.fill: sh = Part.Face(sh)
|
||||
sh = self.applyTrans(sh)
|
||||
|
@ -938,6 +1012,11 @@ def insert(filename,docname):
|
|||
def export(exportList,filename):
|
||||
"called when freecad exports a file"
|
||||
|
||||
svg_export_style = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Draft").GetInt("svg_export_style")
|
||||
if svg_export_style != 0 and svg_export_style != 1:
|
||||
print "unknown svg export style, switching to Translated"
|
||||
svg_export_style = 0
|
||||
|
||||
# finding sheet size
|
||||
minx = 10000
|
||||
miny = 10000
|
||||
|
@ -950,7 +1029,13 @@ def export(exportList,filename):
|
|||
if v.Point.x > maxx: maxx = v.Point.x
|
||||
if v.Point.y < miny: miny = v.Point.y
|
||||
if v.Point.y > maxy: maxy = v.Point.y
|
||||
margin = (maxx-minx)*.01
|
||||
if svg_export_style == 0:
|
||||
# translated-style exports get a bit of a margin
|
||||
margin = (maxx-minx)*.01
|
||||
else:
|
||||
# raw-style exports get no margin
|
||||
margin = 0
|
||||
|
||||
minx -= margin
|
||||
maxx += margin
|
||||
miny -= margin
|
||||
|
@ -958,26 +1043,38 @@ def export(exportList,filename):
|
|||
sizex = maxx-minx
|
||||
sizey = maxy-miny
|
||||
miny += margin
|
||||
boty = sizey+miny
|
||||
|
||||
# writing header
|
||||
# we specify the svg width and height in FreeCAD's physical units (mm),
|
||||
# and specify the viewBox so that user units maps one-to-one to mm
|
||||
svg = pythonopen(filename,'wb')
|
||||
svg.write('<?xml version="1.0"?>\n')
|
||||
svg.write('<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"')
|
||||
svg.write(' "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">\n')
|
||||
svg.write('<svg')
|
||||
svg.write(' width="' + str(sizex) + '" height="' + str(sizey) + '"')
|
||||
svg.write(' viewBox="0 0 ' + str(sizex) + ' ' + str(sizey) + '"')
|
||||
svg.write(' width="' + str(sizex) + 'mm" height="' + str(sizey) + 'mm"')
|
||||
if svg_export_style == 0:
|
||||
# translated-style exports have the viewbox starting at X=0, Y=0
|
||||
svg.write(' viewBox="0 0 ' + str(sizex) + ' ' + str(sizey) + '"')
|
||||
else:
|
||||
# raw-style exports have the viewbox starting at X=0, Y=-height
|
||||
# we need the funny Y here because SVG is upside down, and we
|
||||
# flip the sketch right-way up with a scale later
|
||||
svg.write(' viewBox="0 ' + str(sizey * -1.0) + ' ' + str(sizex) + ' ' + str(sizey) + '"')
|
||||
svg.write(' xmlns="http://www.w3.org/2000/svg" version="1.1"')
|
||||
svg.write('>\n')
|
||||
|
||||
# writing paths
|
||||
for ob in exportList:
|
||||
svg.write('<g transform="translate('+str(-minx)+','+str(-miny+(2*margin))+') scale(1,-1)">\n')
|
||||
if svg_export_style == 0:
|
||||
# translated-style exports have the entire sketch translated to fit in the X>0, Y>0 quadrant
|
||||
svg.write('<g transform="translate('+str(-minx)+','+str(-miny+(2*margin))+') scale(1,-1)">\n')
|
||||
else:
|
||||
# raw-style exports do not translate the sketch
|
||||
svg.write('<g transform="scale(1,-1)">\n')
|
||||
svg.write(Draft.getSVG(ob))
|
||||
svg.write('</g>\n')
|
||||
|
||||
# closing
|
||||
svg.write('</svg>')
|
||||
svg.close()
|
||||
FreeCAD.Console.PrintMessage("successfully exported "+filename)
|
||||
|
|
|
@ -50,11 +50,7 @@ class VersionControl:
|
|||
def __init__(self):
|
||||
self.rev = ""
|
||||
self.date = ""
|
||||
self.range = ""
|
||||
self.url = ""
|
||||
self.time = ""
|
||||
self.mods = "Src not modified"
|
||||
self.mixed = "Src not mixed"
|
||||
|
||||
def extractInfo(self, srcdir):
|
||||
return False
|
||||
|
@ -67,11 +63,7 @@ class VersionControl:
|
|||
for line in lines:
|
||||
line = string.replace(line,'$WCREV$',self.rev)
|
||||
line = string.replace(line,'$WCDATE$',self.date)
|
||||
line = string.replace(line,'$WCRANGE$',self.range)
|
||||
line = string.replace(line,'$WCURL$',self.url)
|
||||
line = string.replace(line,'$WCNOW$',self.time)
|
||||
line = string.replace(line,'$WCMODS?Src modified:Src not modified$',self.mods)
|
||||
line = string.replace(line,'$WCMIXED?Src mixed:Src not mixed$',self.mixed)
|
||||
content.append(line)
|
||||
return content
|
||||
|
||||
|
@ -82,9 +74,7 @@ class UnknownControl(VersionControl):
|
|||
return False
|
||||
self.rev = "Unknown"
|
||||
self.date = "Unknown"
|
||||
self.range = "Unknown"
|
||||
self.url = "Unknown"
|
||||
self.time = "Unknown"
|
||||
return True
|
||||
|
||||
def printInfo(self):
|
||||
|
@ -104,13 +94,10 @@ class DebianChangelog(VersionControl):
|
|||
r=re.search("bzr(\\d+)",c)
|
||||
if r != None:
|
||||
self.rev = r.groups()[0] + " (Launchpad)"
|
||||
self.range = self.rev
|
||||
|
||||
t = time.localtime()
|
||||
self.url = "https://code.launchpad.net/~vcs-imports/freecad/trunk"
|
||||
#self.time = time.asctime()
|
||||
self.date = ("%d/%02d/%02d %02d:%02d:%02d") % (t.tm_year, t.tm_mon, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec)
|
||||
self.time = ("%d/%02d/%02d %02d:%02d:%02d") % (t.tm_year, t.tm_mon, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec)
|
||||
self.url = "https://code.launchpad.net/~vcs-imports/freecad/trunk"
|
||||
return True
|
||||
|
||||
def printInfo(self):
|
||||
|
@ -121,8 +108,6 @@ class BazaarControl(VersionControl):
|
|||
info=os.popen("bzr log -l 1 %s" % (srcdir)).read()
|
||||
if len(info) == 0:
|
||||
return False
|
||||
#Get the current local date
|
||||
self.time = time.strftime("%Y/%m/%d %H:%M:%S")
|
||||
lines=info.split("\n")
|
||||
for i in lines:
|
||||
r = re.match("^revno: (\\d+)$", i)
|
||||
|
@ -151,7 +136,6 @@ class GitControl(VersionControl):
|
|||
if len(info) == 0:
|
||||
return False
|
||||
self.rev='%04d (Git)' % (info.count('\n'))
|
||||
self.range='%04d' % (info.count('\n'))
|
||||
# date/time
|
||||
info=os.popen("git log -1 --date=iso").read()
|
||||
info=info.split("\n")
|
||||
|
@ -159,9 +143,7 @@ class GitControl(VersionControl):
|
|||
r = re.match("^Date:\\W+(\\d+-\\d+-\\d+\\W+\\d+:\\d+:\\d+)", i)
|
||||
if r != None:
|
||||
self.date = r.groups()[0].replace('-','/')
|
||||
self.time = self.date
|
||||
break
|
||||
#self.time = time.strftime("%Y/%m/%d %H:%M:%S")
|
||||
self.url = "Unknown"
|
||||
info=os.popen("git remote -v").read()
|
||||
info=info.split("\n")
|
||||
|
@ -170,11 +152,20 @@ class GitControl(VersionControl):
|
|||
if r != None:
|
||||
self.url = r.groups()[0]
|
||||
break
|
||||
self.hash=os.popen("git log -1 --pretty=format:%H").read()
|
||||
self.branch=os.popen("git branch").read().split('\n')[0][2:]
|
||||
return True
|
||||
|
||||
def printInfo(self):
|
||||
print "git"
|
||||
|
||||
def writeVersion(self, lines):
|
||||
content = VersionControl.writeVersion(self, lines)
|
||||
content.append('// Git relevant stuff\n')
|
||||
content.append('#define FCRepositoryHash "%s"\n' % (self.hash))
|
||||
content.append('#define FCRepositoryBranch "%s"\n' % (self.branch))
|
||||
return content
|
||||
|
||||
class MercurialControl(VersionControl):
|
||||
def extractInfo(self, srcdir):
|
||||
return False
|
||||
|
|
104
src/Tools/makedist.py
Normal file
104
src/Tools/makedist.py
Normal file
|
@ -0,0 +1,104 @@
|
|||
#! python
|
||||
# -*- coding: utf-8 -*-
|
||||
# (c) 2006 Werner Mayer LGPL
|
||||
#
|
||||
# Python script to make source tarballs.
|
||||
#
|
||||
|
||||
import sys, os, getopt, tarfile, gzip, time, StringIO, platform, shutil
|
||||
|
||||
def main():
|
||||
srcdir="."
|
||||
bindir="."
|
||||
dfsg=False
|
||||
check=False
|
||||
wta=""
|
||||
try:
|
||||
opts, args = getopt.getopt(sys.argv[1:], "sb:", ["srcdir=","bindir=","dfsg", "check"])
|
||||
except getopt.GetoptError:
|
||||
pass
|
||||
|
||||
for o, a in opts:
|
||||
if o in ("-s", "--srcdir"):
|
||||
srcdir = a
|
||||
if o in ("-b", "--bindir"):
|
||||
bindir = a
|
||||
if o in ("--dfsg"):
|
||||
dfsg = True
|
||||
wta = "--worktree-attributes"
|
||||
if o in ("--check"):
|
||||
check = True
|
||||
|
||||
if dfsg:
|
||||
gitattr = open("src/.gitattributes","w")
|
||||
gitattr.write("zipios++ export-ignore\n")
|
||||
gitattr.write("Pivy-0.5 export-ignore\n")
|
||||
gitattr.write("Pivy export-ignore\n")
|
||||
gitattr.close()
|
||||
|
||||
# revision number
|
||||
info=os.popen("git rev-list HEAD").read()
|
||||
revision='%04d' % (info.count('\n'))
|
||||
|
||||
PACKAGE_NAME = 'freecad'
|
||||
version = "0.13.%s" % (revision)
|
||||
|
||||
DIRNAME = "%(p)s-%(v)s" % {'p': PACKAGE_NAME, 'v': version}
|
||||
TARNAME = DIRNAME + '.tar'
|
||||
TGZNAME = DIRNAME + '.tar.gz'
|
||||
if dfsg:
|
||||
TGZNAME = DIRNAME + '-dfsg.tar.gz'
|
||||
|
||||
verfile = open("%s/src/Build/Version.h" % (bindir), 'r')
|
||||
verstream = StringIO.StringIO(verfile.read())
|
||||
verfile.close()
|
||||
verinfo = tarfile.TarInfo(DIRNAME + "/src/Build/Version.h")
|
||||
verinfo.mode = 0660
|
||||
verinfo.size = len(verstream.getvalue())
|
||||
verinfo.mtime = time.time()
|
||||
|
||||
print "git archive %s --prefix=%s/ HEAD" % (wta, DIRNAME)
|
||||
if platform.system() == 'Windows':
|
||||
os.popen("git archive %s --prefix=%s/ --output=%s HEAD"
|
||||
% (wta, DIRNAME, TARNAME)).read()
|
||||
|
||||
tar = tarfile.TarFile(mode="a", name=TARNAME)
|
||||
tar.addfile(verinfo, verstream)
|
||||
tar.close()
|
||||
|
||||
out = gzip.open(TGZNAME, "wb")
|
||||
tardata = open(TARNAME, 'rb')
|
||||
out.write(tardata.read())
|
||||
out.close()
|
||||
tardata.close()
|
||||
os.remove(TARNAME)
|
||||
else:
|
||||
tardata = os.popen("git archive %s --prefix=%s/ HEAD"
|
||||
% (wta, DIRNAME)).read()
|
||||
tarstream = StringIO.StringIO(tardata)
|
||||
|
||||
tar = tarfile.TarFile(mode="a", fileobj=tarstream)
|
||||
tar.addfile(verinfo, verstream)
|
||||
tar.close()
|
||||
|
||||
out = gzip.open(TGZNAME, "wb")
|
||||
out.write(tarstream.getvalue())
|
||||
out.close()
|
||||
|
||||
if dfsg:
|
||||
os.remove("src/.gitattributes")
|
||||
print "Created " + TGZNAME
|
||||
# Unpack and build
|
||||
if check:
|
||||
archive=tarfile.open(mode='r:gz',name=TGZNAME)
|
||||
archive.extractall(bindir)
|
||||
builddir = os.path.join(bindir, DIRNAME)
|
||||
cwd = os.getcwd()
|
||||
os.chdir(builddir)
|
||||
os.system("cmake .")
|
||||
os.system("make")
|
||||
os.chdir(cwd)
|
||||
shutil.rmtree(builddir)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
Loading…
Reference in New Issue
Block a user