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
fc.sh export-ignore
UpdateResources.bat export-ignore
BuildVersion.bat export-ignore
*.sln 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)
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)
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)

View File

@ -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;

View File

@ -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

View File

@ -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
}

View File

@ -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

View File

@ -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">&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>
</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>

View File

@ -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"

View File

@ -85,6 +85,7 @@ protected:
protected Q_SLOTS:
virtual void on_licenseButton_clicked();
virtual void on_copyButton_clicked();
private:
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.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

View File

@ -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

View File

@ -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 &amp; display)</string>
</property>
</item>
<item>
<property name="text">
<string>Raw (for CAM)</string>
</property>
</item>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>

View File

@ -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 *********************************************************

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:
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)

View File

@ -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
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()