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:
jriegel 2012-02-11 18:21:09 +00:00
commit f53f1cee84
18 changed files with 52238 additions and 13461 deletions

1
.gitattributes vendored
View File

@ -11,5 +11,6 @@ mkinstalldirs export-ignore
package export-ignore package export-ignore
fc.sh export-ignore fc.sh export-ignore
UpdateResources.bat export-ignore UpdateResources.bat export-ignore
BuildVersion.bat export-ignore
*.sln export-ignore *.sln export-ignore
WindowsInstaller export-ignore WindowsInstaller export-ignore

View File

@ -467,3 +467,26 @@ if(FREECAD_MAINTAINERS_BUILD AND NOT WIN32)
#ADD_CUSTOM_TARGET(DIST make package_source) #ADD_CUSTOM_TARGET(DIST make package_source)
endif(FREECAD_MAINTAINERS_BUILD AND NOT WIN32) 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)

View File

@ -22,9 +22,13 @@ elseif(FREECAD_BUILD_GUI AND FREECAD_LIBPACK_CHECKFILE7X)
elseif(FREECAD_BUILD_GUI) elseif(FREECAD_BUILD_GUI)
find_path(COIN_VERSION3 Inventor/scxml/ScXML.h ${COIN3D_INCLUDE_DIR}) find_path(COIN_VERSION3 Inventor/scxml/ScXML.h ${COIN3D_INCLUDE_DIR})
if (COIN_VERSION3) if (COIN_VERSION3)
if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/Pivy-0.5)
add_subdirectory(Pivy-0.5) add_subdirectory(Pivy-0.5)
endif (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/Pivy-0.5)
else (COIN_VERSION3) else (COIN_VERSION3)
if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/Pivy)
add_subdirectory(Pivy) add_subdirectory(Pivy)
endif (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/Pivy)
endif(COIN_VERSION3) endif(COIN_VERSION3)
endif(FREECAD_BUILD_GUI AND FREECAD_LIBPACK_CHECKFILE6X) endif(FREECAD_BUILD_GUI AND FREECAD_LIBPACK_CHECKFILE6X)

View File

@ -1028,12 +1028,18 @@ void Application::initConfig(int argc, char ** argv)
// only for 'BuildVersionMajor'. // only for 'BuildVersionMajor'.
if (App::Application::Config().find("BuildVersionMajor") == App::Application::Config().end()) { if (App::Application::Config().find("BuildVersionMajor") == App::Application::Config().end()) {
std::stringstream str; str << FCVersionMajor << "." << FCVersionMinor; std::stringstream str; str << FCVersionMajor << "." << FCVersionMinor;
App::Application::Config()["ExeVersion"] = str.str(); App::Application::Config()["ExeVersion" ] = str.str();
App::Application::Config()["BuildVersionMajor"] = FCVersionMajor; App::Application::Config()["BuildVersionMajor" ] = FCVersionMajor;
App::Application::Config()["BuildVersionMinor"] = FCVersionMinor; App::Application::Config()["BuildVersionMinor" ] = FCVersionMinor;
App::Application::Config()["BuildRevision"] = FCRevision; App::Application::Config()["BuildRevision" ] = FCRevision;
App::Application::Config()["BuildRepositoryURL"] = FCRepositoryURL; App::Application::Config()["BuildRepositoryURL" ] = FCRepositoryURL;
App::Application::Config()["BuildRevisionDate"] = FCCurrentDateT; 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; _argc = argc;

View File

@ -68,6 +68,7 @@ if(SWIG_FOUND)
add_definitions(-DHAVE_SWIG=1) add_definitions(-DHAVE_SWIG=1)
endif(SWIG_FOUND) endif(SWIG_FOUND)
if (EXISTS ${CMAKE_SOURCE_DIR}/src/zipios++)
SET(zipios_SRCS SET(zipios_SRCS
../zipios++/backbuffer.h ../zipios++/backbuffer.h
../zipios++/basicentry.cpp ../zipios++/basicentry.cpp
@ -121,6 +122,12 @@ SET(zipios_SRCS
../zipios++/zipoutputstream.h ../zipios++/zipoutputstream.h
) )
SOURCE_GROUP("zipios" FILES ${zipios_SRCS}) 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 SET(pycxx_SRCS
../CXX/Config.hxx ../CXX/Config.hxx

View File

@ -176,8 +176,11 @@ std::string FileInfo::getTempFileName(const char* FileName, const char* Path)
else else
std::strcat(buf, "/fileXXXXXX"); std::strcat(buf, "/fileXXXXXX");
/*int id =*/ (void) mkstemp(buf); int id = mkstemp(buf);
//FILE* file = fdopen(id, "w"); if (id > -1) {
FILE* file = fdopen(id, "w");
fclose(file);
}
return std::string(buf); return std::string(buf);
#endif #endif
} }

View File

@ -1,18 +1,10 @@
/// Version Number // Version Number
#define FCVersionMajor "0" #define FCVersionMajor "0"
#define FCVersionMinor "13" #define FCVersionMinor "13"
#define FCVersionName "Vulcan" #define FCVersionName "Vulcan"
#define FCRevision "$WCREV$" //Highest committed revision number #define FCRevision "$WCREV$" //Highest committed revision number
#define FCRevisionDate "$WCDATE$" //Date of highest committed revision #define FCRevisionDate "$WCDATE$" //Date of highest committed revision
#define FCRevisionRange "$WCRANGE$" //Update revision range
#define FCRepositoryURL "$WCURL$" //Repository URL of the working copy #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

View File

@ -16,13 +16,17 @@
<property name="modal"> <property name="modal">
<bool>true</bool> <bool>true</bool>
</property> </property>
<layout class="QGridLayout"> <layout class="QGridLayout" name="gridLayout">
<property name="margin"> <item row="0" column="0" colspan="3">
<number>9</number> <widget class="QLabel" name="labelSplashPicture">
<property name="text">
<string/>
</property> </property>
<property name="spacing"> <property name="alignment">
<number>6</number> <set>Qt::AlignCenter</set>
</property> </property>
</widget>
</item>
<item row="1" column="1"> <item row="1" column="1">
<spacer> <spacer>
<property name="orientation"> <property name="orientation">
@ -36,15 +40,18 @@
</property> </property>
</spacer> </spacer>
</item> </item>
<item row="0" column="0" colspan="3"> <item row="2" column="0">
<widget class="QLabel" name="labelSplashPicture"> <spacer>
<property name="text"> <property name="orientation">
<string/> <enum>Qt::Horizontal</enum>
</property> </property>
<property name="alignment"> <property name="sizeHint" stdset="0">
<set>Qt::AlignCenter</set> <size>
<width>31</width>
<height>20</height>
</size>
</property> </property>
</widget> </spacer>
</item> </item>
<item row="2" column="1"> <item row="2" column="1">
<layout class="QVBoxLayout"> <layout class="QVBoxLayout">
@ -161,6 +168,34 @@
</property> </property>
</widget> </widget>
</item> </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">&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;/head&gt;&lt;body style=&quot; white-space: pre-wrap; font-family:MS Shell Dlg 2; font-size:7.8pt; font-weight:400; font-style:normal; text-decoration:none;&quot;&gt;&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;&quot;&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;Unknown&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QLabel" name="labelBuildHash">
<property name="text">
<string notr="true">&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;/head&gt;&lt;body style=&quot; white-space: pre-wrap; font-family:MS Shell Dlg 2; font-size:7.8pt; font-weight:400; font-style:normal; text-decoration:none;&quot;&gt;&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;&quot;&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;Unknown&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</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> </layout>
</item> </item>
</layout> </layout>
@ -178,19 +213,6 @@
</property> </property>
</spacer> </spacer>
</item> </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"> <item row="3" column="1">
<spacer> <spacer>
<property name="orientation"> <property name="orientation">
@ -219,6 +241,13 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<widget class="QPushButton" name="copyButton">
<property name="text">
<string>Copy to clipboard</string>
</property>
</widget>
</item>
<item> <item>
<spacer> <spacer>
<property name="orientation"> <property name="orientation">
@ -239,19 +268,6 @@
</property> </property>
</widget> </widget>
</item> </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> </layout>
</item> </item>
</layout> </layout>
@ -264,7 +280,7 @@
</customwidget> </customwidget>
</customwidgets> </customwidgets>
<resources> <resources>
<include location="Icons/resource.qrc"/> <include location="../../../FreeCAD/src/Gui/Icons/resource.qrc"/>
</resources> </resources>
<connections> <connections>
<connection> <connection>

View File

@ -23,8 +23,11 @@
#include "PreCompiled.h" #include "PreCompiled.h"
#ifndef _PreComp_ #ifndef _PreComp_
# include <QApplication>
# include <QClipboard>
# include <QMutex> # include <QMutex>
# include <QSysInfo> # include <QSysInfo>
# include <QTextStream>
# include <QWaitCondition> # include <QWaitCondition>
#endif #endif
@ -248,18 +251,18 @@ static QString getPlatform()
void AboutDialog::setupLabels() void AboutDialog::setupLabels()
{ {
QString exeName = QString::fromAscii(App::Application::Config()["ExeName"].c_str()); std::map<std::string, std::string>& config = App::Application::Config();
std::map<std::string,std::string>& cfg = App::Application::Config(); QString exeName = QString::fromAscii(config["ExeName"].c_str());
std::map<std::string,std::string>::iterator it = cfg.find("WindowTitle"); std::map<std::string,std::string>::iterator it = config.find("WindowTitle");
if (it != cfg.end()) if (it != config.end())
exeName = QString::fromUtf8(it->second.c_str()); 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')) ); banner = banner.left( banner.indexOf(QLatin1Char('\n')) );
QString major = QString::fromAscii(App::Application::Config()["BuildVersionMajor"].c_str()); QString major = QString::fromAscii(config["BuildVersionMajor"].c_str());
QString minor = QString::fromAscii(App::Application::Config()["BuildVersionMinor"].c_str()); QString minor = QString::fromAscii(config["BuildVersionMinor"].c_str());
QString build = QString::fromAscii(App::Application::Config()["BuildRevision"].c_str()); QString build = QString::fromAscii(config["BuildRevision"].c_str());
QString disda = QString::fromAscii(App::Application::Config()["BuildRevisionDate"].c_str()); QString disda = QString::fromAscii(config["BuildRevisionDate"].c_str());
QString mturl = QString::fromAscii(App::Application::Config()["MaintainerUrl"].c_str()); QString mturl = QString::fromAscii(config["MaintainerUrl"].c_str());
QString author = ui->labelAuthor->text(); QString author = ui->labelAuthor->text();
author.replace(QString::fromAscii("Unknown Application"), exeName); author.replace(QString::fromAscii("Unknown Application"), exeName);
@ -283,10 +286,56 @@ void AboutDialog::setupLabels()
platform.replace(QString::fromAscii("Unknown"), platform.replace(QString::fromAscii("Unknown"),
QString::fromAscii("%1 (%2-bit)").arg(getPlatform()).arg(QSysInfo::WordSize)); QString::fromAscii("%1 (%2-bit)").arg(getPlatform()).arg(QSysInfo::WordSize));
ui->labelBuildPlatform->setText(platform); 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_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" #include "moc_Splashscreen.cpp"

View File

@ -85,6 +85,7 @@ protected:
protected Q_SLOTS: protected Q_SLOTS:
virtual void on_licenseButton_clicked(); virtual void on_licenseButton_clicked();
virtual void on_copyButton_clicked();
private: private:
Ui_AboutApplication* ui; Ui_AboutApplication* ui;

View File

@ -140,6 +140,7 @@ class ComponentTaskPanel:
QtCore.QObject.connect(self.addButton, QtCore.SIGNAL("clicked()"), self.addElement) QtCore.QObject.connect(self.addButton, QtCore.SIGNAL("clicked()"), self.addElement)
QtCore.QObject.connect(self.delButton, QtCore.SIGNAL("clicked()"), self.removeElement) 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("itemClicked(QTreeWidgetItem*,int)"), self.check)
QtCore.QObject.connect(self.tree, QtCore.SIGNAL("itemDoubleClicked(QTreeWidgetItem *,int)"), self.editObject)
self.update() self.update()
def isAllowedAlterSelection(self): def isAllowedAlterSelection(self):
@ -225,6 +226,20 @@ class ComponentTaskPanel:
self.obj.ViewObject.finishEditing() self.obj.ViewObject.finishEditing()
return True 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): def retranslateUi(self, TaskPanel):
TaskPanel.setWindowTitle(QtGui.QApplication.translate("Arch", "Components", None, QtGui.QApplication.UnicodeUTF8)) TaskPanel.setWindowTitle(QtGui.QApplication.translate("Arch", "Components", None, QtGui.QApplication.UnicodeUTF8))
self.delButton.setText(QtGui.QApplication.translate("Arch", "Remove", None, QtGui.QApplication.UnicodeUTF8)) self.delButton.setText(QtGui.QApplication.translate("Arch", "Remove", None, QtGui.QApplication.UnicodeUTF8))
@ -252,7 +267,6 @@ class Component:
self.Type = "Component" self.Type = "Component"
self.Subvolume = None self.Subvolume = None
class ViewProviderComponent: class ViewProviderComponent:
"A default View Provider for Component objects" "A default View Provider for Component objects"
def __init__(self,vobj): def __init__(self,vobj):
@ -296,3 +310,17 @@ class ViewProviderComponent:
FreeCADGui.Control.closeDialog() FreeCADGui.Control.closeDialog()
return 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

View File

@ -256,18 +256,11 @@ def formatObject(target,origin=None):
if "ShapeColor" in obrep.PropertiesList: obrep.ShapeColor = fcol if "ShapeColor" in obrep.PropertiesList: obrep.ShapeColor = fcol
else: else:
matchrep = origin.ViewObject matchrep = origin.ViewObject
if ("LineWidth" in obrep.PropertiesList) and \ for p in matchrep.PropertiesList:
("LineWidth" in matchrep.PropertiesList): if not p in ["DisplayMode","BoundingBox","Proxy","RootNode"]:
obrep.LineWidth = matchrep.LineWidth if p in obrep.PropertiesList:
if ("PointColor" in obrep.PropertiesList) and \ val = getattr(matchrep,p)
("PointColor" in matchrep.PropertiesList): setattr(obrep,p,val)
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
if matchrep.DisplayMode in obrep.listDisplayModes(): if matchrep.DisplayMode in obrep.listDisplayModes():
obrep.DisplayMode = matchrep.DisplayMode obrep.DisplayMode = matchrep.DisplayMode
@ -516,48 +509,52 @@ def makeText(stringslist,point=Vector(0,0,0),screen=False):
select(obj) select(obj)
return obj return obj
def makeCopy(obj): def makeCopy(obj,force=None,reparent=False):
'''makeCopy(object): returns an exact copy of an object''' '''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)) newobj = FreeCAD.ActiveDocument.addObject(obj.Type,getRealName(obj.Name))
_Rectangle(newobj) _Rectangle(newobj)
_ViewProviderRectangle(newobj.ViewObject) _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)) newobj = FreeCAD.ActiveDocument.addObject(obj.Type,getRealName(obj.Name))
_Wire(newobj) _Wire(newobj)
_ViewProviderWire(newobj.ViewObject) _ViewProviderWire(newobj.ViewObject)
elif getType(obj) == "Circle": elif (getType(obj) == "Circle") or (force == "Circle"):
newobj = FreeCAD.ActiveDocument.addObject(obj.Type,getRealName(obj.Name)) newobj = FreeCAD.ActiveDocument.addObject(obj.Type,getRealName(obj.Name))
_Circle(newobj) _Circle(newobj)
_ViewProviderCircle(newobj.ViewObject) _ViewProviderDraft(newobj.ViewObject)
elif getType(obj) == "Polygon": elif (getType(obj) == "Polygon") or (force == "Polygon"):
newobj = FreeCAD.ActiveDocument.addObject(obj.Type,getRealName(obj.Name)) newobj = FreeCAD.ActiveDocument.addObject(obj.Type,getRealName(obj.Name))
_Polygon(newobj) _Polygon(newobj)
_ViewProviderPolygon(newobj.ViewObject) _ViewProviderPolygon(newobj.ViewObject)
elif getType(obj) == "BSpline": elif (getType(obj) == "BSpline") or (force == "BSpline"):
newobj = FreeCAD.ActiveDocument.addObject(obj.Type,getRealName(obj.Name)) newobj = FreeCAD.ActiveDocument.addObject(obj.Type,getRealName(obj.Name))
_BSpline(newobj) _BSpline(newobj)
_ViewProviderBSpline(newobj.ViewObject) _ViewProviderBSpline(newobj.ViewObject)
elif getType(obj) == "Block": elif (getType(obj) == "Block") or (force == "BSpline"):
newobj = FreeCAD.ActiveDocument.addObject(obj.Type,getRealName(obj.Name)) newobj = FreeCAD.ActiveDocument.addObject(obj.Type,getRealName(obj.Name))
_Block(newobj) _Block(newobj)
_ViewProviderDraftPart(newobj.ViewObject) _ViewProviderDraftPart(newobj.ViewObject)
elif getType(obj) == "Structure": elif (getType(obj) == "Structure") or (force == "Structure"):
import ArchStructure import ArchStructure
newobj = FreeCAD.ActiveDocument.addObject(obj.Type,getRealName(obj.Name)) newobj = FreeCAD.ActiveDocument.addObject(obj.Type,getRealName(obj.Name))
ArchStructure._Structure(newobj) ArchStructure._Structure(newobj)
ArchStructure._ViewProviderStructure(newobj.ViewObject) ArchStructure._ViewProviderStructure(newobj.ViewObject)
elif getType(obj) == "Wall": elif (getType(obj) == "Wall") or (force == "Wall"):
import ArchWall import ArchWall
newobj = FreeCAD.ActiveDocument.addObject(obj.Type,getRealName(obj.Name)) newobj = FreeCAD.ActiveDocument.addObject(obj.Type,getRealName(obj.Name))
ArchWall._Wall(newobj) ArchWall._Wall(newobj)
ArchWall._ViewProviderWall(newobj.ViewObject) ArchWall._ViewProviderWall(newobj.ViewObject)
elif getType(obj) == "Window": elif (getType(obj) == "Window") or (force == "Window"):
import ArchWindow import ArchWindow
newobj = FreeCAD.ActiveDocument.addObject(obj.Type,getRealName(obj.Name)) newobj = FreeCAD.ActiveDocument.addObject(obj.Type,getRealName(obj.Name))
ArchWindow._Window(newobj) ArchWindow._Window(newobj)
Archwindow._ViewProviderWindow(newobj.ViewObject) Archwindow._ViewProviderWindow(newobj.ViewObject)
elif getType(obj) == "Cell": elif (getType(obj) == "Cell") or (force == "Cell"):
import ArchCell import ArchCell
newobj = FreeCAD.ActiveDocument.addObject(obj.Type,getRealName(obj.Name)) newobj = FreeCAD.ActiveDocument.addObject(obj.Type,getRealName(obj.Name))
ArchCell._Cell(newobj) ArchCell._Cell(newobj)
@ -569,8 +566,19 @@ def makeCopy(obj):
print "Error: Object type cannot be copied" print "Error: Object type cannot be copied"
return None return None
for p in obj.PropertiesList: for p in obj.PropertiesList:
if not p in ["Proxy"]:
if p in newobj.PropertiesList: if p in newobj.PropertiesList:
setattr(newobj,p,obj.getPropertyByName(p)) 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) formatObject(newobj,obj)
return newobj return newobj
@ -685,7 +693,7 @@ def move(objectslist,vector,copy=False):
if copy: if copy:
newobj = FreeCAD.ActiveDocument.addObject("App::FeaturePython",getRealName(obj.Name)) newobj = FreeCAD.ActiveDocument.addObject("App::FeaturePython",getRealName(obj.Name))
_Dimension(newobj) _Dimension(newobj)
_DimensionViewProvider(newobj.ViewObject) _ViewProviderDimension(newobj.ViewObject)
else: else:
newobj = obj newobj = obj
newobj.Start = obj.Start.add(vector) newobj.Start = obj.Start.add(vector)
@ -1402,6 +1410,57 @@ def clone(obj,delta=None):
cl.Placement.move(delta) cl.Placement.move(delta)
return cl 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 # Python Features definitions
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
@ -1539,10 +1598,13 @@ class _ViewProviderDimension:
if hasattr(obj.ViewObject,"DisplayMode"): if hasattr(obj.ViewObject,"DisplayMode"):
if obj.ViewObject.DisplayMode == "3D": if obj.ViewObject.DisplayMode == "3D":
offset = fcvec.neg(offset) offset = fcvec.neg(offset)
if hasattr(obj.ViewObject,"TextPosition"):
if obj.ViewObject.TextPosition == Vector(0,0,0): if obj.ViewObject.TextPosition == Vector(0,0,0):
tbase = midpoint.add(offset) tbase = midpoint.add(offset)
else: else:
tbase = obj.ViewObject.TextPosition tbase = obj.ViewObject.TextPosition
else:
tbase = midpoint.add(offset)
rot = FreeCAD.Placement(fcvec.getPlaneRotation(u,v,norm)).Rotation.Q rot = FreeCAD.Placement(fcvec.getPlaneRotation(u,v,norm)).Rotation.Q
return p1,p2,p3,p4,tbase,norm,rot return p1,p2,p3,p4,tbase,norm,rot
@ -1966,6 +2028,7 @@ class _Rectangle:
def __init__(self, obj): def __init__(self, obj):
obj.addProperty("App::PropertyDistance","Length","Base","Length of the rectangle") obj.addProperty("App::PropertyDistance","Length","Base","Length of the rectangle")
obj.addProperty("App::PropertyDistance","Height","Base","Height of the rectange") 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.Proxy = self
obj.Length=1 obj.Length=1
obj.Height=1 obj.Height=1
@ -1980,12 +2043,18 @@ class _Rectangle:
def createGeometry(self,fp): def createGeometry(self,fp):
import Part import Part
from draftlibs import fcgeo
plm = fp.Placement plm = fp.Placement
p1 = Vector(0,0,0) p1 = Vector(0,0,0)
p2 = Vector(p1.x+fp.Length,p1.y,p1.z) p2 = Vector(p1.x+fp.Length,p1.y,p1.z)
p3 = Vector(p1.x+fp.Length,p1.y+fp.Height,p1.z) p3 = Vector(p1.x+fp.Length,p1.y+fp.Height,p1.z)
p4 = Vector(p1.x,p1.y+fp.Height,p1.z) p4 = Vector(p1.x,p1.y+fp.Height,p1.z)
shape = Part.makePolygon([p1,p2,p3,p4,p1]) 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) shape = Part.Face(shape)
fp.Shape = shape fp.Shape = shape
fp.Placement = plm fp.Placement = plm
@ -2017,9 +2086,9 @@ class _Circle:
"The Circle object" "The Circle object"
def __init__(self, obj): def __init__(self, obj):
obj.addProperty("App::PropertyAngle","FirstAngle","Arc", obj.addProperty("App::PropertyAngle","FirstAngle","Base",
"Start angle of the arc") "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)") "End angle of the arc (for a full circle, give it same value as First Angle)")
obj.addProperty("App::PropertyDistance","Radius","Base", obj.addProperty("App::PropertyDistance","Radius","Base",
"Radius of the circle") "Radius of the circle")
@ -2060,6 +2129,7 @@ class _Wire:
"The start point of this line") "The start point of this line")
obj.addProperty("App::PropertyVector","End","Base", obj.addProperty("App::PropertyVector","End","Base",
"The end point of this line") "The end point of this line")
obj.addProperty("App::PropertyDistance","FilletRadius","Base","Radius to use to fillet the corners")
obj.Proxy = self obj.Proxy = self
obj.Closed = False obj.Closed = False
self.Type = "Wire" self.Type = "Wire"
@ -2068,7 +2138,7 @@ class _Wire:
self.createGeometry(fp) self.createGeometry(fp)
def onChanged(self, fp, prop): def onChanged(self, fp, prop):
if prop in ["Points","Closed","Base","Tool"]: if prop in ["Points","Closed","Base","Tool","FilletRadius"]:
self.createGeometry(fp) self.createGeometry(fp)
if prop == "Points": if prop == "Points":
if fp.Start != fp.Points[0]: if fp.Start != fp.Points[0]:
@ -2121,6 +2191,11 @@ class _Wire:
fp.Points.pop() fp.Points.pop()
if fp.Closed and (len(fp.Points) > 2): if fp.Closed and (len(fp.Points) > 2):
shape = Part.makePolygon(fp.Points+[fp.Points[0]]) 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) shape = Part.Face(shape)
else: else:
edges = [] edges = []
@ -2130,6 +2205,11 @@ class _Wire:
edges.append(Part.Line(lp,p).toShape()) edges.append(Part.Line(lp,p).toShape())
lp = p lp = p
shape = Part.Wire(edges) 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.Shape = shape
fp.Placement = plm fp.Placement = plm
@ -2178,6 +2258,7 @@ class _Polygon:
obj.addProperty("App::PropertyInteger","FacesNumber","Base","Number of faces") obj.addProperty("App::PropertyInteger","FacesNumber","Base","Number of faces")
obj.addProperty("App::PropertyDistance","Radius","Base","Radius of the control circle") 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::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.DrawMode = ['inscribed','circumscribed']
obj.FacesNumber = 3 obj.FacesNumber = 3
obj.Radius = 1 obj.Radius = 1
@ -2193,6 +2274,7 @@ class _Polygon:
def createGeometry(self,fp): def createGeometry(self,fp):
import Part import Part
from draftlibs import fcgeo
plm = fp.Placement plm = fp.Placement
angle = (math.pi*2)/fp.FacesNumber angle = (math.pi*2)/fp.FacesNumber
if fp.DrawMode == 'inscribed': if fp.DrawMode == 'inscribed':
@ -2205,6 +2287,11 @@ class _Polygon:
pts.append(Vector(delta*math.cos(ang),delta*math.sin(ang),0)) pts.append(Vector(delta*math.cos(ang),delta*math.sin(ang),0))
pts.append(pts[0]) pts.append(pts[0])
shape = Part.makePolygon(pts) 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) shape = Part.Face(shape)
fp.Shape = shape fp.Shape = shape
fp.Placement = plm fp.Placement = plm

File diff suppressed because it is too large Load Diff

View File

@ -356,6 +356,43 @@ If color mapping is choosed, you must choose a color mapping file containing a t
</item> </item>
</layout> </layout>
</item> </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 &amp; display)</string>
</property>
</item>
<item>
<property name="text">
<string>Raw (for CAM)</string>
</property>
</item>
</widget>
</item>
</layout>
</item>
</layout> </layout>
</widget> </widget>
</item> </item>

View File

@ -1196,6 +1196,280 @@ def arcFromSpline(edge):
except: except:
print "couldn't make a circle out of this edge" 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 ********************************************************* # circle functions *********************************************************
def getBoundaryAngles(angle,alist): def getBoundaryAngles(angle,alist):

View File

@ -28,12 +28,15 @@ __url__ = ["http://free-cad.sourceforge.net"]
''' '''
This script imports SVG files in FreeCAD. Currently only reads the following entities: This script imports SVG files in FreeCAD. Currently only reads the following entities:
paths, lines, circular arcs ,rects, circles, ellipses, polygons, polylines. paths, lines, circular arcs ,rects, circles, ellipses, polygons, polylines.
currently unsupported: image, rounded rect(rx,ry), elliptical arcs currently unsupported: use, image
''' '''
#ToDo: #ToDo:
# elliptical arc segments
# rounded rects (elliptical arcs)
# ignoring CDATA # 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 import xml.sax, string, FreeCAD, os, math, re, Draft
from draftlibs import fcvec from draftlibs import fcvec
@ -48,154 +51,154 @@ except: draftui = None
pythonopen = open pythonopen = open
svgcolors = { svgcolors = {
'Pink': [255, 192, 203], 'Pink': (255, 192, 203),
'Blue': [0, 0, 255], 'Blue': (0, 0, 255),
'Honeydew': [240, 255, 240], 'Honeydew': (240, 255, 240),
'Purple': [128, 0, 128], 'Purple': (128, 0, 128),
'Fuchsia': [255, 0, 255], 'Fuchsia': (255, 0, 255),
'LawnGreen': [124, 252, 0], 'LawnGreen': (124, 252, 0),
'Amethyst': [153, 102, 204], 'Amethyst': (153, 102, 204),
'Crimson': [220, 20, 60], 'Crimson': (220, 20, 60),
'White': [255, 255, 255], 'White': (255, 255, 255),
'NavajoWhite': [255, 222, 173], 'NavajoWhite': (255, 222, 173),
'Cornsilk': [255, 248, 220], 'Cornsilk': (255, 248, 220),
'Bisque': [255, 228, 196], 'Bisque': (255, 228, 196),
'PaleGreen': [152, 251, 152], 'PaleGreen': (152, 251, 152),
'Brown': [165, 42, 42], 'Brown': (165, 42, 42),
'DarkTurquoise': [0, 206, 209], 'DarkTurquoise': (0, 206, 209),
'DarkGreen': [0, 100, 0], 'DarkGreen': (0, 100, 0),
'MediumOrchid': [186, 85, 211], 'MediumOrchid': (186, 85, 211),
'Chocolate': [210, 105, 30], 'Chocolate': (210, 105, 30),
'PapayaWhip': [255, 239, 213], 'PapayaWhip': (255, 239, 213),
'Olive': [128, 128, 0], 'Olive': (128, 128, 0),
'Silver': [192, 192, 192], 'Silver': (192, 192, 192),
'PeachPuff': [255, 218, 185], 'PeachPuff': (255, 218, 185),
'Plum': [221, 160, 221], 'Plum': (221, 160, 221),
'DarkGoldenrod': [184, 134, 11], 'DarkGoldenrod': (184, 134, 11),
'SlateGrey': [112, 128, 144], 'SlateGrey': (112, 128, 144),
'MintCream': [245, 255, 250], 'MintCream': (245, 255, 250),
'CornflowerBlue': [100, 149, 237], 'CornflowerBlue': (100, 149, 237),
'Gold': [255, 215, 0], 'Gold': (255, 215, 0),
'HotPink': [255, 105, 180], 'HotPink': (255, 105, 180),
'DarkBlue': [0, 0, 139], 'DarkBlue': (0, 0, 139),
'LimeGreen': [50, 205, 50], 'LimeGreen': (50, 205, 50),
'DeepSkyBlue': [0, 191, 255], 'DeepSkyBlue': (0, 191, 255),
'DarkKhaki': [189, 183, 107], 'DarkKhaki': (189, 183, 107),
'LightGrey': [211, 211, 211], 'LightGrey': (211, 211, 211),
'Yellow': [255, 255, 0], 'Yellow': (255, 255, 0),
'Gainsboro': [220, 220, 220], 'Gainsboro': (220, 220, 220),
'MistyRose': [255, 228, 225], 'MistyRose': (255, 228, 225),
'SandyBrown': [244, 164, 96], 'SandyBrown': (244, 164, 96),
'DeepPink': [255, 20, 147], 'DeepPink': (255, 20, 147),
'Magenta': [255, 0, 255], 'Magenta': (255, 0, 255),
'AliceBlue': [240, 248, 255], 'AliceBlue': (240, 248, 255),
'DarkCyan': [0, 139, 139], 'DarkCyan': (0, 139, 139),
'DarkSlateGrey': [47, 79, 79], 'DarkSlateGrey': (47, 79, 79),
'GreenYellow': [173, 255, 47], 'GreenYellow': (173, 255, 47),
'DarkOrchid': [153, 50, 204], 'DarkOrchid': (153, 50, 204),
'OliveDrab': [107, 142, 35], 'OliveDrab': (107, 142, 35),
'Chartreuse': [127, 255, 0], 'Chartreuse': (127, 255, 0),
'Peru': [205, 133, 63], 'Peru': (205, 133, 63),
'Orange': [255, 165, 0], 'Orange': (255, 165, 0),
'Red': [255, 0, 0], 'Red': (255, 0, 0),
'Wheat': [245, 222, 179], 'Wheat': (245, 222, 179),
'LightCyan': [224, 255, 255], 'LightCyan': (224, 255, 255),
'LightSeaGreen': [32, 178, 170], 'LightSeaGreen': (32, 178, 170),
'BlueViolet': [138, 43, 226], 'BlueViolet': (138, 43, 226),
'LightSlateGrey': [119, 136, 153], 'LightSlateGrey': (119, 136, 153),
'Cyan': [0, 255, 255], 'Cyan': (0, 255, 255),
'MediumPurple': [147, 112, 219], 'MediumPurple': (147, 112, 219),
'MidnightBlue': [25, 25, 112], 'MidnightBlue': (25, 25, 112),
'FireBrick': [178, 34, 34], 'FireBrick': (178, 34, 34),
'PaleTurquoise': [175, 238, 238], 'PaleTurquoise': (175, 238, 238),
'PaleGoldenrod': [238, 232, 170], 'PaleGoldenrod': (238, 232, 170),
'Gray': [128, 128, 128], 'Gray': (128, 128, 128),
'MediumSeaGreen': [60, 179, 113], 'MediumSeaGreen': (60, 179, 113),
'Moccasin': [255, 228, 181], 'Moccasin': (255, 228, 181),
'Ivory': [255, 255, 240], 'Ivory': (255, 255, 240),
'DarkSlateBlue': [72, 61, 139], 'DarkSlateBlue': (72, 61, 139),
'Beige': [245, 245, 220], 'Beige': (245, 245, 220),
'Green': [0, 128, 0], 'Green': (0, 128, 0),
'SlateBlue': [106, 90, 205], 'SlateBlue': (106, 90, 205),
'Teal': [0, 128, 128], 'Teal': (0, 128, 128),
'Azure': [240, 255, 255], 'Azure': (240, 255, 255),
'LightSteelBlue': [176, 196, 222], 'LightSteelBlue': (176, 196, 222),
'DimGrey': [105, 105, 105], 'DimGrey': (105, 105, 105),
'Tan': [210, 180, 140], 'Tan': (210, 180, 140),
'AntiqueWhite': [250, 235, 215], 'AntiqueWhite': (250, 235, 215),
'SkyBlue': [135, 206, 235], 'SkyBlue': (135, 206, 235),
'GhostWhite': [248, 248, 255], 'GhostWhite': (248, 248, 255),
'MediumTurquoise': [72, 209, 204], 'MediumTurquoise': (72, 209, 204),
'FloralWhite': [255, 250, 240], 'FloralWhite': (255, 250, 240),
'LavenderBlush': [255, 240, 245], 'LavenderBlush': (255, 240, 245),
'SeaGreen': [46, 139, 87], 'SeaGreen': (46, 139, 87),
'Lavender': [230, 230, 250], 'Lavender': (230, 230, 250),
'BlanchedAlmond': [255, 235, 205], 'BlanchedAlmond': (255, 235, 205),
'DarkOliveGreen': [85, 107, 47], 'DarkOliveGreen': (85, 107, 47),
'DarkSeaGreen': [143, 188, 143], 'DarkSeaGreen': (143, 188, 143),
'SpringGreen': [0, 255, 127], 'SpringGreen': (0, 255, 127),
'Navy': [0, 0, 128], 'Navy': (0, 0, 128),
'Orchid': [218, 112, 214], 'Orchid': (218, 112, 214),
'SaddleBrown': [139, 69, 19], 'SaddleBrown': (139, 69, 19),
'IndianRed': [205, 92, 92], 'IndianRed': (205, 92, 92),
'Snow': [255, 250, 250], 'Snow': (255, 250, 250),
'SteelBlue': [70, 130, 180], 'SteelBlue': (70, 130, 180),
'MediumSlateBlue': [123, 104, 238], 'MediumSlateBlue': (123, 104, 238),
'Black': [0, 0, 0], 'Black': (0, 0, 0),
'LightBlue': [173, 216, 230], 'LightBlue': (173, 216, 230),
'Turquoise': [64, 224, 208], 'Turquoise': (64, 224, 208),
'MediumVioletRed': [199, 21, 133], 'MediumVioletRed': (199, 21, 133),
'DarkViolet': [148, 0, 211], 'DarkViolet': (148, 0, 211),
'DarkGray': [169, 169, 169], 'DarkGray': (169, 169, 169),
'Salmon': [250, 128, 114], 'Salmon': (250, 128, 114),
'DarkMagenta': [139, 0, 139], 'DarkMagenta': (139, 0, 139),
'Tomato': [255, 99, 71], 'Tomato': (255, 99, 71),
'WhiteSmoke': [245, 245, 245], 'WhiteSmoke': (245, 245, 245),
'Goldenrod': [218, 165, 32], 'Goldenrod': (218, 165, 32),
'MediumSpringGreen': [0, 250, 154], 'MediumSpringGreen': (0, 250, 154),
'DodgerBlue': [30, 144, 255], 'DodgerBlue': (30, 144, 255),
'Aqua': [0, 255, 255], 'Aqua': (0, 255, 255),
'ForestGreen': [34, 139, 34], 'ForestGreen': (34, 139, 34),
'LemonChiffon': [255, 250, 205], 'LemonChiffon': (255, 250, 205),
'LightSlateGray': [119, 136, 153], 'LightSlateGray': (119, 136, 153),
'SlateGray': [112, 128, 144], 'SlateGray': (112, 128, 144),
'LightGray': [211, 211, 211], 'LightGray': (211, 211, 211),
'Indigo': [75, 0, 130], 'Indigo': (75, 0, 130),
'CadetBlue': [95, 158, 160], 'CadetBlue': (95, 158, 160),
'LightYellow': [255, 255, 224], 'LightYellow': (255, 255, 224),
'DarkOrange': [255, 140, 0], 'DarkOrange': (255, 140, 0),
'PowderBlue': [176, 224, 230], 'PowderBlue': (176, 224, 230),
'RoyalBlue': [65, 105, 225], 'RoyalBlue': (65, 105, 225),
'Sienna': [160, 82, 45], 'Sienna': (160, 82, 45),
'Thistle': [216, 191, 216], 'Thistle': (216, 191, 216),
'Lime': [0, 255, 0], 'Lime': (0, 255, 0),
'Seashell': [255, 245, 238], 'Seashell': (255, 245, 238),
'DarkRed': [139, 0, 0], 'DarkRed': (139, 0, 0),
'LightSkyBlue': [135, 206, 250], 'LightSkyBlue': (135, 206, 250),
'YellowGreen': [154, 205, 50], 'YellowGreen': (154, 205, 50),
'Aquamarine': [127, 255, 212], 'Aquamarine': (127, 255, 212),
'LightCoral': [240, 128, 128], 'LightCoral': (240, 128, 128),
'DarkSlateGray': [47, 79, 79], 'DarkSlateGray': (47, 79, 79),
'Khaki': [240, 230, 140], 'Khaki': (240, 230, 140),
'DarkGrey': [169, 169, 169], 'DarkGrey': (169, 169, 169),
'BurlyWood': [222, 184, 135], 'BurlyWood': (222, 184, 135),
'LightGoldenrodYellow': [250, 250, 210], 'LightGoldenrodYellow': (250, 250, 210),
'MediumBlue': [0, 0, 205], 'MediumBlue': (0, 0, 205),
'DarkSalmon': [233, 150, 122], 'DarkSalmon': (233, 150, 122),
'RosyBrown': [188, 143, 143], 'RosyBrown': (188, 143, 143),
'LightSalmon': [255, 160, 122], 'LightSalmon': (255, 160, 122),
'PaleVioletRed': [219, 112, 147], 'PaleVioletRed': (219, 112, 147),
'Coral': [255, 127, 80], 'Coral': (255, 127, 80),
'Violet': [238, 130, 238], 'Violet': (238, 130, 238),
'Grey': [128, 128, 128], 'Grey': (128, 128, 128),
'LightGreen': [144, 238, 144], 'LightGreen': (144, 238, 144),
'Linen': [250, 240, 230], 'Linen': (250, 240, 230),
'OrangeRed': [255, 69, 0], 'OrangeRed': (255, 69, 0),
'DimGray': [105, 105, 105], 'DimGray': (105, 105, 105),
'Maroon': [128, 0, 0], 'Maroon': (128, 0, 0),
'LightPink': [255, 182, 193], 'LightPink': (255, 182, 193),
'MediumAquamarine': [102, 205, 170], 'MediumAquamarine': (102, 205, 170),
'OldLace': [253, 245, 230] 'OldLace': (253, 245, 230)
} }
def getcolor(color): def getcolor(color):
@ -227,6 +230,85 @@ def getsize(width):
except ValueError: except ValueError:
return width 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): def getrgb(color):
"returns a rgb value #000000 from a freecad color" "returns a rgb value #000000 from a freecad color"
r = str(hex(int(color[0]*255)))[2:].zfill(2) r = str(hex(int(color[0]*255)))[2:].zfill(2)
@ -364,163 +446,79 @@ class svgHandler(xml.sax.ContentHandler):
obj = Draft.makeDimension(p1,p2,p3) obj = Draft.makeDimension(p1,p2,p3)
self.applyTrans(obj) self.applyTrans(obj)
self.format(obj) self.format(obj)
pathdata = []
self.lastdim = obj self.lastdim = obj
data['d']=[]
pathcommandsre=re.compile('\s*?([mMlLhHvVaAcCqQsStTzZ])\s*?([^mMlLhHvVaAcCqQsStTzZ]*)\s*?',re.DOTALL) pathcommandsre=re.compile('\s*?([mMlLhHvVaAcCqQsStTzZ])\s*?([^mMlLhHvVaAcCqQsStTzZ]*)\s*?',re.DOTALL)
for d,pointsstr in pathcommandsre.findall(' '.join(data['d'])): for d,pointsstr in pathcommandsre.findall(' '.join(data['d'])):
#for d in pathdata: relative = d.islower()
if (d == "M"): pointlist = [float(str1) for str1 in pointsstr.replace(',',' ').split()]
command = "move" if (d == "M" or d == "m"):
relative = False x = pointlist.pop(0)
point = [] y = pointlist.pop(0)
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: if path:
sh = Part.Wire(path) #sh = Part.Wire(path)
sh = makewire(path)
if self.fill: sh = Part.Face(sh) if self.fill: sh = Part.Face(sh)
sh = self.applyTrans(sh) sh = self.applyTrans(sh)
obj = self.doc.addObject("Part::Feature",pathname) obj = self.doc.addObject("Part::Feature",pathname)
obj.Shape = sh obj.Shape = sh
self.format(obj) self.format(obj)
path = [] path = []
if firstvec: #if firstvec:
lastvec = firstvec #Move relative to last move command not last draw command # lastvec = firstvec #Move relative to last move command not last draw command
if relative: if relative:
lastvec = lastvec.add(Vector(point[0],-point[1],0)) lastvec = lastvec.add(Vector(x,-y,0))
command="line"
else: else:
lastvec = Vector(point[0],-point[1],0) lastvec = Vector(x,-y,0)
firstvec = lastvec firstvec = lastvec
print "move ",lastvec print "move ",lastvec
command = "line"
lastpole = None lastpole = None
point = [] if (d == "L" or d == "l") or \
elif (len(point)==2) and (command=="line"): ((d == 'm' or d == 'M') and pointlist) :
for x,y in zip(pointlist[0::2],pointlist[1::2]):
if relative: if relative:
currentvec = lastvec.add(Vector(point[0],-point[1],0)) currentvec = lastvec.add(Vector(x,-y,0))
else: else:
currentvec = Vector(point[0],-point[1],0) currentvec = Vector(x,-y,0)
if not fcvec.equals(lastvec,currentvec): if not fcvec.equals(lastvec,currentvec):
seg = Part.Line(lastvec,currentvec).toShape() seg = Part.Line(lastvec,currentvec).toShape()
print "line ",lastvec,currentvec print "line ",lastvec,currentvec
lastvec = currentvec lastvec = currentvec
path.append(seg) path.append(seg)
lastpole = None lastpole = None
point = [] elif (d == "H" or d == "h"):
elif (len(point)==1) and (command=="horizontal"): for x in pointlist:
if relative: if relative:
currentvec = lastvec.add(Vector(point[0],0,0)) currentvec = lastvec.add(Vector(x,0,0))
else: else:
lasty = path[-1].y lasty = path[-1].y
currentvec = Vector(point[0],lasty,0) currentvec = Vector(x,lasty,0)
seg = Part.Line(lastvec,currentvec).toShape() seg = Part.Line(lastvec,currentvec).toShape()
lastvec = currentvec lastvec = currentvec
lastpole = None lastpole = None
path.append(seg) path.append(seg)
point = [] elif (d == "V" or d == "v"):
elif (len(point)==1) and (command=="vertical"): for y in pointlist:
if relative: if relative:
currentvec = lastvec.add(Vector(0,-point[0],0)) currentvec = lastvec.add(Vector(0,-y,0))
else: else:
lastx = path[-1].x lastx = path[-1].x
currentvec = Vector(lastx,-point[0],0) currentvec = Vector(lastx,-y,0)
seg = Part.Line(lastvec,currentvec).toShape() seg = Part.Line(lastvec,currentvec).toShape()
lastvec = currentvec lastvec = currentvec
lastpole = None lastpole = None
path.append(seg) path.append(seg)
point = [] elif (d == "A" or d == "a"):
elif (len(point)==7) and (command=="arc"): 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 #support for large-arc and x-rotation are missing
rx,ry,xrotation, largeflag, sweepflag = point[0:5]
if relative: if relative:
currentvec = lastvec.add(Vector(point[-2],-point[-1],0)) currentvec = lastvec.add(Vector(x,-y,0))
else: else:
currentvec = Vector(point[-2],-point[-1],0) currentvec = Vector(x,-y,0)
chord = currentvec.sub(lastvec) chord = currentvec.sub(lastvec)
if (not largeflag) and abs(rx-ry) < 10**(-1*Draft.precision()): # small circular arc
# perp = chord.cross(Vector(0,0,-1)) # perp = chord.cross(Vector(0,0,-1))
# here is a better way to find the perpendicular # here is a better way to find the perpendicular
if sweepflag == 1: if sweepflag == 1:
@ -536,31 +534,71 @@ class svgHandler(xml.sax.ContentHandler):
perp = fcvec.scale(perp,s/perp.Length) perp = fcvec.scale(perp,s/perp.Length)
midpoint = lastvec.add(chord.add(perp)) midpoint = lastvec.add(chord.add(perp))
seg = Part.Arc(lastvec,midpoint,currentvec).toShape() 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 lastvec = currentvec
lastpole = None lastpole = None
path.append(seg) path.append(seg)
point = [] elif (d == "C" or d == "c") or\
elif (command=="cubic") and (((smooth==False) and (len(point)==6)) or (smooth==True and (len(point)==4))) : (d =="S" or d == "s"):
smooth = (d == 'S' or d == 's')
if smooth: if smooth:
if relative: piter = zip(pointlist[2::4],pointlist[3::4],pointlist[0::4],pointlist[1::4],pointlist[2::4],pointlist[3::4])
currentvec = lastvec.add(Vector(point[2],-point[3],0))
pole2 = lastvec.add(Vector(point[0],-point[1],0))
else: else:
currentvec = Vector(point[2],-point[3],0) piter = zip(pointlist[0::6],pointlist[1::6],pointlist[2::6],pointlist[3::6],pointlist[4::6],pointlist[5::6])
pole2 = Vector(point[0],-point[1],0) for p1x,p1y,p2x,p2y,x,y in piter:
if smooth:
if lastpole is not None and lastpole[0]=='cubic': if lastpole is not None and lastpole[0]=='cubic':
pole1 = lastvec.sub(lastpole[1]).add(lastvec) pole1 = lastvec.sub(lastpole[1]).add(lastvec)
else: else:
pole1 = lastvec pole1 = lastvec
else: #not smooth
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))
else: else:
currentvec = Vector(point[4],-point[5],0) if relative:
pole1 = Vector(point[0],-point[1],0) pole1 = lastvec.add(Vector(p1x,-p1y,0))
pole2 = Vector(point[2],-point[3],0) else:
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): if not fcvec.equals(currentvec,lastvec):
mainv = currentvec.sub(lastvec) mainv = currentvec.sub(lastvec)
@ -568,8 +606,8 @@ class svgHandler(xml.sax.ContentHandler):
pole2v = currentvec.add(pole2) pole2v = currentvec.add(pole2)
print "cubic curve data:",mainv.normalize(),pole1v.normalize(),pole2v.normalize() print "cubic curve data:",mainv.normalize(),pole1v.normalize(),pole2v.normalize()
if True and \ if True and \
pole1.distanceToLine(lastvec,currentvec) < 20**(-1*Draft.precision()) and \ pole1.distanceToLine(lastvec,currentvec) < 10**(-1*(2+Draft.precision())) and \
pole2.distanceToLine(lastvec,currentvec) < 20**(-1*Draft.precision()): pole2.distanceToLine(lastvec,currentvec) < 10**(-1*(2+Draft.precision())):
print "straight segment" print "straight segment"
seg = Part.Line(lastvec,currentvec).toShape() seg = Part.Line(lastvec,currentvec).toShape()
else: else:
@ -581,54 +619,50 @@ class svgHandler(xml.sax.ContentHandler):
lastvec = currentvec lastvec = currentvec
lastpole = ('cubic',pole2) lastpole = ('cubic',pole2)
path.append(seg) path.append(seg)
point = [] elif (d == "Q" or d == "q") or\
(d =="T" or d == "t"):
elif (command=="quadratic") and (((smooth==False) and (len(point)==4)) or (smooth==True and (len(point)==2))) : smooth = (d == 'T' or d == 't')
if smooth: if smooth:
if relative: piter = zip(pointlist[1::2],pointlist[1::2],pointlist[0::2],pointlist[1::2])
currentvec = lastvec.add(Vector(point[0],-point[1],0))
else: else:
currentvec = Vector(point[0],-point[1],0) piter = zip(pointlist[0::4],pointlist[1::4],pointlist[2::4],pointlist[3::4])
for px,py,x,y in piter:
if smooth:
if lastpole is not None and lastpole[0]=='quadratic': if lastpole is not None and lastpole[0]=='quadratic':
pole1 = lastvec.sub(lastpole[1]).add(lastvec) pole = lastvec.sub(lastpole[1]).add(lastvec)
else:
pole = lastvec
else: else:
pole1 = lastvec
else: #not smooth
if relative: if relative:
currentvec = lastvec.add(Vector(point[2],-point[3],0)) pole = lastvec.add(Vector(px,-py,0))
pole1 = lastvec.add(Vector(point[0],-point[1],0))
else: else:
currentvec = Vector(point[2],-point[3],0) pole = Vector(px,-py,0)
pole1 = Vector(point[0],-point[1],0) if relative:
currentvec = lastvec.add(Vector(x,-y,0))
else:
currentvec = Vector(x,-y,0)
if not fcvec.equals(currentvec,lastvec): 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" print "straight segment"
seg = Part.Line(lastvec,currentvec).toShape() seg = Part.Line(lastvec,currentvec).toShape()
else: else:
print "quadratic bezier segment" print "quadratic bezier segment"
b = Part.BezierCurve() b = Part.BezierCurve()
b.setPoles([lastvec,pole1,currentvec]) b.setPoles([lastvec,pole,currentvec])
seg = b.toShape() seg = b.toShape()
print "connect ",lastvec,currentvec print "connect ",lastvec,currentvec
lastvec = currentvec lastvec = currentvec
lastpole = ('quadratic',pole1) lastpole = ('quadratic',pole)
path.append(seg) path.append(seg)
point = [] elif (d == "Z") or (d == "z"):
#while pointlist or command:
else:
if (command == "close"):
if not fcvec.equals(lastvec,firstvec): if not fcvec.equals(lastvec,firstvec):
seg = Part.Line(lastvec,firstvec).toShape() seg = Part.Line(lastvec,firstvec).toShape()
path.append(seg) path.append(seg)
if path: #the path should be closed by now if path: #the path should be closed by now
sh = Part.Wire(path) #sh=makewire(path,True)
if not sh.isClosed: sh=makewire(path,donttry=True)
#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) if self.fill: sh = Part.Face(sh)
sh = self.applyTrans(sh) sh = self.applyTrans(sh)
obj = self.doc.addObject("Part::Feature",pathname) obj = self.doc.addObject("Part::Feature",pathname)
@ -636,11 +670,12 @@ class svgHandler(xml.sax.ContentHandler):
self.format(obj) self.format(obj)
path = [] path = []
if firstvec: if firstvec:
lastvec = firstvec #Move relative to last move command not last draw command lastvec = firstvec #Move relative to recent draw command
point = [] point = []
command = None command = None
if path: if path:
sh = Part.Wire(path) sh=makewire(path,checkclosed=False)
#sh = Part.Wire(path)
if self.fill: sh = Part.Face(sh) if self.fill: sh = Part.Face(sh)
sh = self.applyTrans(sh) sh = self.applyTrans(sh)
obj = self.doc.addObject("Part::Feature",pathname) obj = self.doc.addObject("Part::Feature",pathname)
@ -653,9 +688,9 @@ class svgHandler(xml.sax.ContentHandler):
if name == "rect": if name == "rect":
if not pathname: pathname = 'Rectangle' if not pathname: pathname = 'Rectangle'
edges = [] edges = []
# if ('rx' not in data or data['rx'] < 10**(-1*Draft.precision())) and \ 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 ('ry' not in data or data['ry'] < 10**(-1*Draft.precision())): #negative values are invalid
if True: # if True:
p1 = Vector(data['x'],-data['y'],0) p1 = Vector(data['x'],-data['y'],0)
p2 = Vector(data['x']+data['width'],-data['y'],0) p2 = Vector(data['x']+data['width'],-data['y'],0)
p3 = Vector(data['x']+data['width'],-data['y']-data['height'],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(p3,p4).toShape())
edges.append(Part.Line(p4,p1).toShape()) edges.append(Part.Line(p4,p1).toShape())
else: #rounded edges else: #rounded edges
#ToTo: check for ry>rx !!!!
rx = data.get('rx') rx = data.get('rx')
ry = data.get('ry') or rx ry = data.get('ry') or rx
rx = rx or ry rx = rx or ry
@ -672,8 +708,46 @@ class svgHandler(xml.sax.ContentHandler):
rx = data['width'] / 2.0 rx = data['width'] / 2.0
if ry > 2 * data['height']: if ry > 2 * data['height']:
ry = data['height'] / 2.0 ry = data['height'] / 2.0
#TBD if rx > ry:
# Part.Ellipse(c,rx,ry).toShape() #needs a proxy object 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) sh = Part.Wire(edges)
if self.fill: sh = Part.Face(sh) if self.fill: sh = Part.Face(sh)
sh = self.applyTrans(sh) sh = self.applyTrans(sh)
@ -938,6 +1012,11 @@ def insert(filename,docname):
def export(exportList,filename): def export(exportList,filename):
"called when freecad exports a file" "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 # finding sheet size
minx = 10000 minx = 10000
miny = 10000 miny = 10000
@ -950,7 +1029,13 @@ def export(exportList,filename):
if v.Point.x > maxx: maxx = v.Point.x if v.Point.x > maxx: maxx = v.Point.x
if v.Point.y < miny: miny = v.Point.y if v.Point.y < miny: miny = v.Point.y
if v.Point.y > maxy: maxy = v.Point.y if v.Point.y > maxy: maxy = v.Point.y
if svg_export_style == 0:
# translated-style exports get a bit of a margin
margin = (maxx-minx)*.01 margin = (maxx-minx)*.01
else:
# raw-style exports get no margin
margin = 0
minx -= margin minx -= margin
maxx += margin maxx += margin
miny -= margin miny -= margin
@ -958,26 +1043,38 @@ def export(exportList,filename):
sizex = maxx-minx sizex = maxx-minx
sizey = maxy-miny sizey = maxy-miny
miny += margin miny += margin
boty = sizey+miny
# writing header # 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 = pythonopen(filename,'wb')
svg.write('<?xml version="1.0"?>\n') svg.write('<?xml version="1.0"?>\n')
svg.write('<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"') 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(' "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">\n')
svg.write('<svg') svg.write('<svg')
svg.write(' width="' + str(sizex) + '" height="' + 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) + '"') 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(' xmlns="http://www.w3.org/2000/svg" version="1.1"')
svg.write('>\n') svg.write('>\n')
# writing paths # writing paths
for ob in exportList: for ob in exportList:
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') 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(Draft.getSVG(ob))
svg.write('</g>\n') svg.write('</g>\n')
# closing # closing
svg.write('</svg>') svg.write('</svg>')
svg.close() svg.close()
FreeCAD.Console.PrintMessage("successfully exported "+filename)

View File

@ -50,11 +50,7 @@ class VersionControl:
def __init__(self): def __init__(self):
self.rev = "" self.rev = ""
self.date = "" self.date = ""
self.range = ""
self.url = "" self.url = ""
self.time = ""
self.mods = "Src not modified"
self.mixed = "Src not mixed"
def extractInfo(self, srcdir): def extractInfo(self, srcdir):
return False return False
@ -67,11 +63,7 @@ class VersionControl:
for line in lines: for line in lines:
line = string.replace(line,'$WCREV$',self.rev) line = string.replace(line,'$WCREV$',self.rev)
line = string.replace(line,'$WCDATE$',self.date) 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,'$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) content.append(line)
return content return content
@ -82,9 +74,7 @@ class UnknownControl(VersionControl):
return False return False
self.rev = "Unknown" self.rev = "Unknown"
self.date = "Unknown" self.date = "Unknown"
self.range = "Unknown"
self.url = "Unknown" self.url = "Unknown"
self.time = "Unknown"
return True return True
def printInfo(self): def printInfo(self):
@ -104,13 +94,10 @@ class DebianChangelog(VersionControl):
r=re.search("bzr(\\d+)",c) r=re.search("bzr(\\d+)",c)
if r != None: if r != None:
self.rev = r.groups()[0] + " (Launchpad)" self.rev = r.groups()[0] + " (Launchpad)"
self.range = self.rev
t = time.localtime() 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.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 return True
def printInfo(self): def printInfo(self):
@ -121,8 +108,6 @@ class BazaarControl(VersionControl):
info=os.popen("bzr log -l 1 %s" % (srcdir)).read() info=os.popen("bzr log -l 1 %s" % (srcdir)).read()
if len(info) == 0: if len(info) == 0:
return False return False
#Get the current local date
self.time = time.strftime("%Y/%m/%d %H:%M:%S")
lines=info.split("\n") lines=info.split("\n")
for i in lines: for i in lines:
r = re.match("^revno: (\\d+)$", i) r = re.match("^revno: (\\d+)$", i)
@ -151,7 +136,6 @@ class GitControl(VersionControl):
if len(info) == 0: if len(info) == 0:
return False return False
self.rev='%04d (Git)' % (info.count('\n')) self.rev='%04d (Git)' % (info.count('\n'))
self.range='%04d' % (info.count('\n'))
# date/time # date/time
info=os.popen("git log -1 --date=iso").read() info=os.popen("git log -1 --date=iso").read()
info=info.split("\n") info=info.split("\n")
@ -159,9 +143,7 @@ class GitControl(VersionControl):
r = re.match("^Date:\\W+(\\d+-\\d+-\\d+\\W+\\d+:\\d+:\\d+)", i) r = re.match("^Date:\\W+(\\d+-\\d+-\\d+\\W+\\d+:\\d+:\\d+)", i)
if r != None: if r != None:
self.date = r.groups()[0].replace('-','/') self.date = r.groups()[0].replace('-','/')
self.time = self.date
break break
#self.time = time.strftime("%Y/%m/%d %H:%M:%S")
self.url = "Unknown" self.url = "Unknown"
info=os.popen("git remote -v").read() info=os.popen("git remote -v").read()
info=info.split("\n") info=info.split("\n")
@ -170,11 +152,20 @@ class GitControl(VersionControl):
if r != None: if r != None:
self.url = r.groups()[0] self.url = r.groups()[0]
break 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 return True
def printInfo(self): def printInfo(self):
print "git" 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): class MercurialControl(VersionControl):
def extractInfo(self, srcdir): def extractInfo(self, srcdir):
return False return False

104
src/Tools/makedist.py Normal file
View 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()