From 9b6492f9d76910556d2e6171a9bb1ac7b250359f Mon Sep 17 00:00:00 2001 From: Yorik van Havre Date: Sat, 24 Mar 2012 00:49:12 -0300 Subject: [PATCH 1/6] Fixed bugs in Arch Window + now builds its shape more correctly + can be inserted in walls --- src/Mod/Arch/ArchWall.py | 31 ++++++++++++++++++++----------- src/Mod/Arch/ArchWindow.py | 9 +++++---- 2 files changed, 25 insertions(+), 15 deletions(-) diff --git a/src/Mod/Arch/ArchWall.py b/src/Mod/Arch/ArchWall.py index b1389556a..5b12b796c 100644 --- a/src/Mod/Arch/ArchWall.py +++ b/src/Mod/Arch/ArchWall.py @@ -339,17 +339,26 @@ class _Wall(ArchComponent.Component): base = base.oldFuse(app.Shape) app.ViewObject.hide() #to be removed for hole in obj.Subtractions: - cut = False - if hasattr(hole,"Proxy"): - if hasattr(hole.Proxy,"Subvolume"): - if hole.Proxy.Subvolume: - print "cutting subvolume",hole.Proxy.Subvolume - base = base.cut(hole.Proxy.Subvolume) - cut = True - if not cut: - if hasattr(obj,"Shape"): - base = base.cut(hole.Shape) - hole.ViewObject.hide() # to be removed + if Draft.getType(hole) == "Window": + # window + if hole.Base and obj.Width: + max_length = 0 + for w in hole.Base.Shape.Wires: + if w.BoundBox.DiagonalLength > max_length: + max_length = w.BoundBox.DiagonalLength + ext = w + f = Part.Face(ext) + l = obj.Width + n = f.normalAt(0,0) + v1 = fcvec.scaleTo(n,l) + f.translate(v1) + v2 = fcvec.neg(v1) + v2 = fcvec.scale(v1,-2) + f = f.extrude(v2) + base = base.cut(f) + elif hasattr(obj,"Shape"): + base = base.cut(hole.Shape) + hole.ViewObject.hide() # to be removed obj.Shape = base if not fcgeo.isNull(pl): obj.Placement = pl diff --git a/src/Mod/Arch/ArchWindow.py b/src/Mod/Arch/ArchWindow.py index f6f1303cb..0e9202f84 100644 --- a/src/Mod/Arch/ArchWindow.py +++ b/src/Mod/Arch/ArchWindow.py @@ -121,15 +121,16 @@ class _Window(ArchComponent.Component): max_length = w.BoundBox.DiagonalLength ext = w wires.remove(ext) - for w in wires: - w.reverse() - wires.insert(0, ext) - shape = Part.Face(wires) + shape = Part.Face(ext) norm = shape.normalAt(0,0) thk = float(obj.WindowParts[(i*5)+3]) if thk: exv = fcvec.scaleTo(norm,thk) shape = shape.extrude(exv) + for w in wires: + f = Part.Face(w) + f = f.extrude(exv) + shape = shape.cut(f) if obj.WindowParts[(i*5)+4]: zof = float(obj.WindowParts[(i*5)+4]) if zof: From e102ab5eca794560bab9b080b8cf8ec3e163e55f Mon Sep 17 00:00:00 2001 From: Yorik van Havre Date: Sat, 24 Mar 2012 11:41:45 -0300 Subject: [PATCH 2/6] Using the Arch window tool when a window is selected now produces a clone --- src/Mod/Arch/ArchWindow.py | 4 ++++ src/Mod/Draft/Draft.py | 8 +++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/Mod/Arch/ArchWindow.py b/src/Mod/Arch/ArchWindow.py index 0e9202f84..ce884801d 100644 --- a/src/Mod/Arch/ArchWindow.py +++ b/src/Mod/Arch/ArchWindow.py @@ -33,6 +33,10 @@ __url__ = "http://free-cad.sourceforge.net" def makeWindow(baseobj=None,name="Window"): '''makeWindow(obj,[name]): creates a window based on the given object''' + if baseobj: + if Draft.getType(baseobj) == "Window": + obj = Draft.clone(baseobj) + return obj obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython",name) _Window(obj) _ViewProviderWindow(obj.ViewObject) diff --git a/src/Mod/Draft/Draft.py b/src/Mod/Draft/Draft.py index e8f25025a..37a7f3148 100644 --- a/src/Mod/Draft/Draft.py +++ b/src/Mod/Draft/Draft.py @@ -1581,8 +1581,11 @@ def clone(obj,delta=None): if not isinstance(obj,list): obj = [obj] cl = FreeCAD.ActiveDocument.addObject("Part::FeaturePython","Clone") + cl.Label = "Clone of " + obj[0].Label _Clone(cl) - _ViewProviderDraftPart(cl.ViewObject) + if gui: + _ViewProviderDraftPart(cl.ViewObject) + formatObject(cl,obj[0]) cl.Objects = obj if delta: cl.Placement.move(delta) @@ -2813,3 +2816,6 @@ class _ViewProviderDraftPart(_ViewProviderDraft): def getIcon(self): return ":/icons/Tree_Part.svg" + def claimChildren(self): + return [] + From 0f6eca5ef8e7a3b428aae5f65eeb4bcc7f1cb31a Mon Sep 17 00:00:00 2001 From: Yorik van Havre Date: Sat, 24 Mar 2012 18:26:01 -0300 Subject: [PATCH 3/6] Bugfixes in Arch Windows --- src/Mod/Arch/ArchWall.py | 37 ++++++++++++++++++++++++------------- src/Mod/Draft/Draft.py | 9 +++++++++ 2 files changed, 33 insertions(+), 13 deletions(-) diff --git a/src/Mod/Arch/ArchWall.py b/src/Mod/Arch/ArchWall.py index 5b12b796c..4799d4abc 100644 --- a/src/Mod/Arch/ArchWall.py +++ b/src/Mod/Arch/ArchWall.py @@ -257,6 +257,25 @@ class _Wall(ArchComponent.Component): if prop in ["Base","Height","Width","Align","Additions","Subtractions"]: self.createGeometry(obj) + def getSubVolume(self,base,width,delta=None): + "returns a subvolume from a base object" + import Part + max_length = 0 + for w in base.Shape.Wires: + if w.BoundBox.DiagonalLength > max_length: + max_length = w.BoundBox.DiagonalLength + f = w + f = Part.Face(f) + n = f.normalAt(0,0) + v1 = fcvec.scaleTo(n,width) + f.translate(v1) + v2 = fcvec.neg(v1) + v2 = fcvec.scale(v1,-2) + f = f.extrude(v2) + if delta: + f.translate(delta) + return f + def createGeometry(self,obj): import Part @@ -342,20 +361,12 @@ class _Wall(ArchComponent.Component): if Draft.getType(hole) == "Window": # window if hole.Base and obj.Width: - max_length = 0 - for w in hole.Base.Shape.Wires: - if w.BoundBox.DiagonalLength > max_length: - max_length = w.BoundBox.DiagonalLength - ext = w - f = Part.Face(ext) - l = obj.Width - n = f.normalAt(0,0) - v1 = fcvec.scaleTo(n,l) - f.translate(v1) - v2 = fcvec.neg(v1) - v2 = fcvec.scale(v1,-2) - f = f.extrude(v2) + f = self.getSubVolume(hole.Base,obj.Width) base = base.cut(f) + elif Draft.isClone(hole,"Window"): + if hole.Objects[0].Base and obj.Width: + f = self.getSubVolume(hole.Objects[0].Base,obj.Width,hole.Placement.Base) + base = base.cut(f) elif hasattr(obj,"Shape"): base = base.cut(hole.Shape) hole.ViewObject.hide() # to be removed diff --git a/src/Mod/Draft/Draft.py b/src/Mod/Draft/Draft.py index 37a7f3148..59c4e16d1 100644 --- a/src/Mod/Draft/Draft.py +++ b/src/Mod/Draft/Draft.py @@ -170,6 +170,15 @@ def getType(obj): return "Group" return "Unknown" +def isClone(obj,objtype): + """isClone(obj,objtype): returns True if the given object is + a clone of an object of the given type""" + if getType(obj) == "Clone": + if len(obj.Objects) == 1: + if getType(obj.Objects[0]) == objtype: + return True + return False + def getGroupNames(): "returns a list of existing groups in the document" glist = [] From 11c1efca7e06e3cb66044b21379dc4e901f9c80a Mon Sep 17 00:00:00 2001 From: wmayer Date: Sun, 25 Mar 2012 11:44:57 +0200 Subject: [PATCH 4/6] Improve I/O of PLY mesh format --- src/Mod/Mesh/App/Core/MeshIO.cpp | 143 ++++++++++++++++++++++++-- src/Mod/Mesh/App/Core/MeshIO.h | 13 ++- src/Mod/Mesh/App/Mesh.cpp | 30 +++++- src/Mod/Mesh/App/Mesh.h | 10 +- src/Mod/Mesh/App/MeshFeaturePyImp.cpp | 40 +++++-- src/Mod/Mesh/App/MeshProperties.cpp | 107 ------------------- src/Mod/Mesh/App/MeshProperties.h | 20 ---- src/Mod/Mesh/App/MeshPyImp.cpp | 1 + src/Mod/Mesh/Gui/Makefile.am | 2 +- src/Mod/Mesh/Gui/ViewProvider.cpp | 97 +++++++++++++++-- src/Mod/Mesh/Gui/ViewProvider.h | 3 + 11 files changed, 308 insertions(+), 158 deletions(-) diff --git a/src/Mod/Mesh/App/Core/MeshIO.cpp b/src/Mod/Mesh/App/Core/MeshIO.cpp index 6c7827734..4003e019c 100644 --- a/src/Mod/Mesh/App/Core/MeshIO.cpp +++ b/src/Mod/Mesh/App/Core/MeshIO.cpp @@ -661,7 +661,8 @@ bool MeshInput::LoadPLY (std::istream &inp) return false; // wrong header std::string line, element; - bool xyz_float=false,xyz_double=false,rgb_value=false; + bool xyz_float=false,xyz_double=false; + MeshIO::Binding rgb_value = MeshIO::OVERALL; while (std::getline(inp, line)) { std::istringstream str(line); str.unsetf(std::ios_base::skipws); @@ -738,7 +739,11 @@ bool MeshInput::LoadPLY (std::istream &inp) xyz_double = true; } else if (name == "red") { - rgb_value = true; + rgb_value = MeshIO::PER_VERTEX; + if (_material) { + _material->binding = MeshIO::PER_VERTEX; + _material->diffuseColor.reserve(v_count); + } } } else if (element == "face") { @@ -753,9 +758,38 @@ bool MeshInput::LoadPLY (std::istream &inp) boost::regex rx_p("^([-+]?[0-9]*)\\.?([0-9]+([eE][-+]?[0-9]+)?)" "\\s+([-+]?[0-9]*)\\.?([0-9]+([eE][-+]?[0-9]+)?)" "\\s+([-+]?[0-9]*)\\.?([0-9]+([eE][-+]?[0-9]+)?)\\s*$"); + boost::regex rx_c("^([-+]?[0-9]*)\\.?([0-9]+([eE][-+]?[0-9]+)?)" + "\\s+([-+]?[0-9]*)\\.?([0-9]+([eE][-+]?[0-9]+)?)" + "\\s+([-+]?[0-9]*)\\.?([0-9]+([eE][-+]?[0-9]+)?)" + "\\s+([0-9]{1,3})\\s+([0-9]{1,3})\\s+([0-9]{1,3})\\s*$"); boost::regex rx_f("^\\s*3\\s+([0-9]+)\\s+([0-9]+)\\s+([0-9]+)\\s*$"); boost::cmatch what; Base::Vector3f pt; + + if (rgb_value == MeshIO::PER_VERTEX) { + int r,g,b; + for (std::size_t i = 0; i < v_count && std::getline(inp, line); i++) { + if (boost::regex_match(line.c_str(), what, rx_c)) { + pt.x = (float)std::atof(what[1].first); + pt.y = (float)std::atof(what[4].first); + pt.z = (float)std::atof(what[7].first); + meshPoints.push_back(pt); + if (_material) { + r = std::min(std::atoi(what[10].first),255); + g = std::min(std::atoi(what[11].first),255); + b = std::min(std::atoi(what[12].first),255); + float fr = (float)r/255.0f; + float fg = (float)g/255.0f; + float fb = (float)b/255.0f; + _material->diffuseColor.push_back(App::Color(fr, fg, fb)); + } + } + else { + return false; + } + } + } + else { for (std::size_t i = 0; i < v_count && std::getline(inp, line); i++) { if (boost::regex_match(line.c_str(), what, rx_p)) { pt.x = (float)std::atof(what[1].first); @@ -767,6 +801,7 @@ bool MeshInput::LoadPLY (std::istream &inp) return false; } } + } int f1, f2, f3; for (std::size_t i = 0; i < f_count && std::getline(inp, line); i++) { if (boost::regex_match(line.c_str(), what, rx_f)) { @@ -777,6 +812,7 @@ bool MeshInput::LoadPLY (std::istream &inp) } } } + // binary else { Base::InputStream is(inp); if (format == binary_little_endian) @@ -789,16 +825,31 @@ bool MeshInput::LoadPLY (std::istream &inp) for (std::size_t i = 0; i < v_count; i++) { is >> pt.x >> pt.y >> pt.z; meshPoints.push_back(pt); - if (rgb_value) + if (rgb_value == MeshIO::PER_VERTEX) { is >> r >> g >> b; + if (_material) { + float fr = (float)r/255.0f; + float fg = (float)g/255.0f; + float fb = (float)b/255.0f; + _material->diffuseColor.push_back(App::Color(fr, fg, fb)); + } + } } } else if (xyz_double) { Base::Vector3d pt; for (std::size_t i = 0; i < v_count; i++) { is >> pt.x >> pt.y >> pt.z; - is >> r >> g >> b; meshPoints.push_back(Base::Vector3f((float)pt.x,(float)pt.y,(float)pt.z)); + if (rgb_value == MeshIO::PER_VERTEX) { + is >> r >> g >> b; + if (_material) { + float fr = (float)r/255.0f; + float fg = (float)g/255.0f; + float fb = (float)b/255.0f; + _material->diffuseColor.push_back(App::Color(fr, fg, fb)); + } + } } } unsigned char n; @@ -1428,7 +1479,12 @@ bool MeshOutput::SaveAny(const char* FileName, MeshIO::Format format) const } else if (fileformat == MeshIO::PLY) { // write file - if (!SavePLY(str)) + if (!SaveBinaryPLY(str)) + throw Base::FileException("Export of PLY mesh failed",FileName); + } + else if (fileformat == MeshIO::APLY) { + // write file + if (!SaveAsciiPLY(str)) throw Base::FileException("Export of PLY mesh failed",FileName); } else if (fileformat == MeshIO::IV) { @@ -1646,7 +1702,7 @@ bool MeshOutput::SaveOFF (std::ostream &out) const return true; } -bool MeshOutput::SavePLY (std::ostream &out) const +bool MeshOutput::SaveBinaryPLY (std::ostream &out) const { const MeshPointArray& rPoints = _rclMesh.GetPoints(); const MeshFacetArray& rFacets = _rclMesh.GetFacets(); @@ -1706,6 +1762,81 @@ bool MeshOutput::SavePLY (std::ostream &out) const return true; } +bool MeshOutput::SaveAsciiPLY (std::ostream &out) const +{ + const MeshPointArray& rPoints = _rclMesh.GetPoints(); + const MeshFacetArray& rFacets = _rclMesh.GetFacets(); + std::size_t v_count = rPoints.size(); + std::size_t f_count = rFacets.size(); + if (!out || out.bad() == true) + return false; + + bool saveVertexColor = (_material && _material->binding == MeshIO::PER_VERTEX + && _material->diffuseColor.size() == rPoints.size()); + out << "ply" << std::endl + << "format ascii 1.0" << std::endl + << "comment Created by FreeCAD " << std::endl + << "element vertex " << v_count << std::endl + << "property float32 x" << std::endl + << "property float32 y" << std::endl + << "property float32 z" << std::endl; + if (saveVertexColor) { + out << "property uchar red" << std::endl + << "property uchar green" << std::endl + << "property uchar blue" << std::endl; + } + out << "element face " << f_count << std::endl + << "property list uchar int vertex_index" << std::endl + << "end_header" << std::endl; + + Base::Vector3f pt; + + out.precision(6); + out.setf(std::ios::fixed | std::ios::showpoint); + if (saveVertexColor) { + for (std::size_t i = 0; i < v_count; i++) { + const MeshPoint& p = rPoints[i]; + if (this->apply_transform) { + Base::Vector3f pt = this->_transform * p; + out << pt.x << " " << pt.y << " " << pt.z; + } + else { + out << p.x << " " << p.y << " " << p.z; + } + + const App::Color& c = _material->diffuseColor[i]; + int r = (int)(255.0f * c.r); + int g = (int)(255.0f * c.g); + int b = (int)(255.0f * c.b); + out << " " << r << " " << g << " " << b << std::endl; + } + } + else { + for (std::size_t i = 0; i < v_count; i++) { + const MeshPoint& p = rPoints[i]; + if (this->apply_transform) { + Base::Vector3f pt = this->_transform * p; + out << pt.x << " " << pt.y << " " << pt.z << std::endl; + } + else { + out << p.x << " " << p.y << " " << p.z << std::endl; + } + } + } + + unsigned int n = 3; + int f1, f2, f3; + for (std::size_t i = 0; i < f_count; i++) { + const MeshFacet& f = rFacets[i]; + f1 = (int)f._aulPoints[0]; + f2 = (int)f._aulPoints[1]; + f3 = (int)f._aulPoints[2]; + out << n << " " << f1 << " " << f2 << " " << f3 << std::endl; + } + + return true; +} + bool MeshOutput::SaveMeshNode (std::ostream &rstrOut) { const MeshPointArray& rPoints = _rclMesh.GetPoints(); diff --git a/src/Mod/Mesh/App/Core/MeshIO.h b/src/Mod/Mesh/App/Core/MeshIO.h index e45d9f64e..b439f1bd2 100644 --- a/src/Mod/Mesh/App/Core/MeshIO.h +++ b/src/Mod/Mesh/App/Core/MeshIO.h @@ -51,6 +51,7 @@ namespace MeshIO { WRZ, NAS, PLY, + APLY, PY }; enum Binding { @@ -74,7 +75,10 @@ struct MeshExport Material class MeshExport MeshInput { public: - MeshInput (MeshKernel &rclM): _rclMesh(rclM){}; + MeshInput (MeshKernel &rclM) + : _rclMesh(rclM), _material(0){} + MeshInput (MeshKernel &rclM, Material* m) + : _rclMesh(rclM), _material(m){} virtual ~MeshInput (void) { } /// Loads the file, decided by extension @@ -106,6 +110,7 @@ public: protected: MeshKernel &_rclMesh; /**< reference to mesh data structure */ + Material* _material; }; /** @@ -138,8 +143,10 @@ public: bool SaveOBJ (std::ostream &rstrOut) const; /** Saves the mesh object into an OFF file. */ bool SaveOFF (std::ostream &rstrOut) const; - /** Saves the mesh object into a PLY file. */ - bool SavePLY (std::ostream &rstrOut) const; + /** Saves the mesh object into a binary PLY file. */ + bool SaveBinaryPLY (std::ostream &rstrOut) const; + /** Saves the mesh object into an ASCII PLY file. */ + bool SaveAsciiPLY (std::ostream &rstrOut) const; /** Saves the mesh object into an XML file. */ void SaveXML (Base::Writer &writer) const; /** Saves a node to an OpenInventor file. */ diff --git a/src/Mod/Mesh/App/Mesh.cpp b/src/Mod/Mesh/App/Mesh.cpp index 47f7a57cf..f7b133a11 100644 --- a/src/Mod/Mesh/App/Mesh.cpp +++ b/src/Mod/Mesh/App/Mesh.cpp @@ -311,10 +311,10 @@ void MeshObject::save(std::ostream& out) const _kernel.Write(out); } -bool MeshObject::load(const char* file) +bool MeshObject::load(const char* file, MeshCore::Material* mat) { MeshCore::MeshKernel kernel; - MeshCore::MeshInput aReader(kernel); + MeshCore::MeshInput aReader(kernel, mat); if (!aReader.LoadAny(file)) return false; @@ -631,6 +631,32 @@ void MeshObject::removeComponents(unsigned long count) deletedFacets(removeIndices); } +unsigned long MeshObject::getPointDegree(const std::vector& indices, + std::vector& point_degree) const +{ + const MeshCore::MeshFacetArray& faces = _kernel.GetFacets(); + std::vector pointDeg(_kernel.CountPoints()); + + for (MeshCore::MeshFacetArray::_TConstIterator it = faces.begin(); it != faces.end(); ++it) { + pointDeg[it->_aulPoints[0]]++; + pointDeg[it->_aulPoints[1]]++; + pointDeg[it->_aulPoints[2]]++; + } + + for (std::vector::const_iterator it = indices.begin(); it != indices.end(); ++it) { + const MeshCore::MeshFacet& face = faces[*it]; + pointDeg[face._aulPoints[0]]--; + pointDeg[face._aulPoints[1]]--; + pointDeg[face._aulPoints[2]]--; + } + + unsigned long countInvalids = std::count_if(pointDeg.begin(), pointDeg.end(), + std::bind2nd(std::equal_to(), 0)); + + point_degree = pointDeg; + return countInvalids; +} + void MeshObject::fillupHoles(unsigned long length, int level, MeshCore::AbstractPolygonTriangulator& cTria) { diff --git a/src/Mod/Mesh/App/Mesh.h b/src/Mod/Mesh/App/Mesh.h index aedc0defc..de42bd381 100644 --- a/src/Mod/Mesh/App/Mesh.h +++ b/src/Mod/Mesh/App/Mesh.h @@ -144,7 +144,7 @@ public: void save(const char* file,MeshCore::MeshIO::Format f=MeshCore::MeshIO::Undefined, const MeshCore::Material* mat = 0) const; void save(std::ostream&) const; - bool load(const char* file); + bool load(const char* file, MeshCore::Material* mat = 0); void load(std::istream&); //@} @@ -177,6 +177,14 @@ public: std::vector > getComponents() const; unsigned long countComponents() const; void removeComponents(unsigned long); + /** + * Checks for the given facet indices what will be the degree for each point + * when these facets are removed from the mesh kernel. + * The point degree information is stored in \a point_degree. The return value + * gices the number of points which will have a degree of zero. + */ + unsigned long getPointDegree(const std::vector& facets, + std::vector& point_degree) const; void fillupHoles(unsigned long, int, MeshCore::AbstractPolygonTriangulator&); void offset(float fSize); void offsetSpecial2(float fSize); diff --git a/src/Mod/Mesh/App/MeshFeaturePyImp.cpp b/src/Mod/Mesh/App/MeshFeaturePyImp.cpp index fb0d60dac..b99e5bee1 100644 --- a/src/Mod/Mesh/App/MeshFeaturePyImp.cpp +++ b/src/Mod/Mesh/App/MeshFeaturePyImp.cpp @@ -77,7 +77,10 @@ PyObject* MeshFeaturePy::smooth(PyObject *args) return NULL; PY_TRY { - getFeaturePtr()->Mesh.smooth(iter, d_max); + Mesh::Feature* obj = getFeaturePtr(); + MeshObject* kernel = obj->Mesh.startEditing(); + kernel->smooth(iter, d_max); + obj->Mesh.finishEditing(); } PY_CATCH; Py_Return; @@ -87,7 +90,10 @@ PyObject* MeshFeaturePy::removeNonManifolds(PyObject *args) { if (!PyArg_ParseTuple(args, "")) return NULL; - getFeaturePtr()->Mesh.removeNonManifolds(); + Mesh::Feature* obj = getFeaturePtr(); + MeshObject* kernel = obj->Mesh.startEditing(); + kernel->removeNonManifolds(); + obj->Mesh.finishEditing(); Py_Return } @@ -97,7 +103,10 @@ PyObject* MeshFeaturePy::fixIndices(PyObject *args) return NULL; PY_TRY { - getFeaturePtr()->Mesh.validateIndices(); + Mesh::Feature* obj = getFeaturePtr(); + MeshObject* kernel = obj->Mesh.startEditing(); + kernel->validateIndices(); + obj->Mesh.finishEditing(); } PY_CATCH; Py_Return; @@ -109,7 +118,10 @@ PyObject* MeshFeaturePy::fixDegenerations(PyObject *args) return NULL; PY_TRY { - getFeaturePtr()->Mesh.validateDegenerations(); + Mesh::Feature* obj = getFeaturePtr(); + MeshObject* kernel = obj->Mesh.startEditing(); + kernel->validateDegenerations(); + obj->Mesh.finishEditing(); } PY_CATCH; Py_Return; @@ -121,7 +133,10 @@ PyObject* MeshFeaturePy::removeDuplicatedFacets(PyObject *args) return NULL; PY_TRY { - getFeaturePtr()->Mesh.removeDuplicatedFacets(); + Mesh::Feature* obj = getFeaturePtr(); + MeshObject* kernel = obj->Mesh.startEditing(); + kernel->removeDuplicatedFacets(); + obj->Mesh.finishEditing(); } PY_CATCH; Py_Return; @@ -133,7 +148,10 @@ PyObject* MeshFeaturePy::removeDuplicatedPoints(PyObject *args) return NULL; PY_TRY { - getFeaturePtr()->Mesh.removeDuplicatedPoints(); + Mesh::Feature* obj = getFeaturePtr(); + MeshObject* kernel = obj->Mesh.startEditing(); + kernel->removeDuplicatedPoints(); + obj->Mesh.finishEditing(); } PY_CATCH; Py_Return; @@ -144,7 +162,10 @@ PyObject* MeshFeaturePy::fixSelfIntersections(PyObject *args) if (!PyArg_ParseTuple(args, "")) return NULL; try { - getFeaturePtr()->Mesh.removeSelfIntersections(); + Mesh::Feature* obj = getFeaturePtr(); + MeshObject* kernel = obj->Mesh.startEditing(); + kernel->removeSelfIntersections(); + obj->Mesh.finishEditing(); } catch (const Base::Exception& e) { PyErr_SetString(PyExc_Exception, e.what()); @@ -158,7 +179,10 @@ PyObject* MeshFeaturePy::removeFoldsOnSurface(PyObject *args) if (!PyArg_ParseTuple(args, "")) return NULL; try { - getFeaturePtr()->Mesh.removeFoldsOnSurface(); + Mesh::Feature* obj = getFeaturePtr(); + MeshObject* kernel = obj->Mesh.startEditing(); + kernel->removeFoldsOnSurface(); + obj->Mesh.finishEditing(); } catch (const Base::Exception& e) { PyErr_SetString(PyExc_Exception, e.what()); diff --git a/src/Mod/Mesh/App/MeshProperties.cpp b/src/Mod/Mesh/App/MeshProperties.cpp index 3c0b41190..9e68cae10 100644 --- a/src/Mod/Mesh/App/MeshProperties.cpp +++ b/src/Mod/Mesh/App/MeshProperties.cpp @@ -390,20 +390,6 @@ void PropertyMeshKernel::transformGeometry(const Base::Matrix4D &rclMat) hasSetValue(); } -void PropertyMeshKernel::deletePointIndices( const std::vector& inds ) -{ - aboutToSetValue(); - _meshObject->deletePoints(inds); - hasSetValue(); -} - -void PropertyMeshKernel::deleteFacetIndices( const std::vector& inds ) -{ - aboutToSetValue(); - _meshObject->deleteFacets(inds); - hasSetValue(); -} - void PropertyMeshKernel::setPointIndices(const std::vector >& inds) { aboutToSetValue(); @@ -413,99 +399,6 @@ void PropertyMeshKernel::setPointIndices(const std::vector& rFaces, - const std::vector& rPoints) -{ - aboutToSetValue(); - _meshObject->addFacets(rFaces, rPoints); - hasSetValue(); -} - -void PropertyMeshKernel::createSegment(const std::vector& segm) -{ - aboutToSetValue(); - _meshObject->addSegment(segm); - hasSetValue(); -} - -void PropertyMeshKernel::smooth(int iter, float d_max) -{ - aboutToSetValue(); - _meshObject->smooth(iter, d_max); - hasSetValue(); -} - -void PropertyMeshKernel::clear() -{ - // clear the underlying mesh kernel and free any allocated memory - aboutToSetValue(); - _meshObject->clear(); - hasSetValue(); -} - -void PropertyMeshKernel::harmonizeNormals() -{ - aboutToSetValue(); - _meshObject->harmonizeNormals(); - hasSetValue(); -} - -void PropertyMeshKernel::removeNonManifolds() -{ - aboutToSetValue(); - _meshObject->removeNonManifolds(); - hasSetValue(); -} - -void PropertyMeshKernel::validateIndices() -{ - aboutToSetValue(); - _meshObject->validateIndices(); - hasSetValue(); -} - -void PropertyMeshKernel::validateDegenerations() -{ - aboutToSetValue(); - _meshObject->validateDegenerations(); - hasSetValue(); -} - -void PropertyMeshKernel::validateDeformations(float fMaxAngle) -{ - aboutToSetValue(); - _meshObject->validateDeformations(fMaxAngle); - hasSetValue(); -} - -void PropertyMeshKernel::removeDuplicatedFacets() -{ - aboutToSetValue(); - _meshObject->removeDuplicatedFacets(); - hasSetValue(); -} - -void PropertyMeshKernel::removeDuplicatedPoints() -{ - aboutToSetValue(); - _meshObject->removeDuplicatedPoints(); - hasSetValue(); -} - -void PropertyMeshKernel::removeSelfIntersections() -{ - aboutToSetValue(); - _meshObject->removeSelfIntersections(); - hasSetValue(); -} - -void PropertyMeshKernel::removeFoldsOnSurface() -{ - aboutToSetValue(); - _meshObject->removeFoldsOnSurface(); - hasSetValue(); -} - PyObject *PropertyMeshKernel::getPyObject(void) { if (!meshPyObject) { diff --git a/src/Mod/Mesh/App/MeshProperties.h b/src/Mod/Mesh/App/MeshProperties.h index af1cd0f8b..04bfb8dee 100644 --- a/src/Mod/Mesh/App/MeshProperties.h +++ b/src/Mod/Mesh/App/MeshProperties.h @@ -179,27 +179,7 @@ public: void finishEditing(); /// Transform the real mesh data void transformGeometry(const Base::Matrix4D &rclMat); - void deletePointIndices ( const std::vector& ); - void deleteFacetIndices ( const std::vector& ); void setPointIndices( const std::vector >& ); - void append(const std::vector& rFaces, - const std::vector& rPoints); - void createSegment(const std::vector& segm); - void smooth(int iter, float d_max); - void clear(); - //@} - - /** @name Mesh validation */ - //@{ - void harmonizeNormals(); - void validateIndices(); - void validateDeformations(float fMaxAngle); - void validateDegenerations(); - void removeDuplicatedPoints(); - void removeDuplicatedFacets(); - void removeNonManifolds(); - void removeSelfIntersections(); - void removeFoldsOnSurface(); //@} /** @name Python interface */ diff --git a/src/Mod/Mesh/App/MeshPyImp.cpp b/src/Mod/Mesh/App/MeshPyImp.cpp index ace103289..a25e3e2f6 100644 --- a/src/Mod/Mesh/App/MeshPyImp.cpp +++ b/src/Mod/Mesh/App/MeshPyImp.cpp @@ -165,6 +165,7 @@ PyObject* MeshPy::write(PyObject *args) ext["NAS" ] = MeshCore::MeshIO::NAS; ext["BDF" ] = MeshCore::MeshIO::NAS; ext["PLY" ] = MeshCore::MeshIO::PLY; + ext["APLY"] = MeshCore::MeshIO::APLY; ext["PY" ] = MeshCore::MeshIO::PY; if (ext.find(Ext) != ext.end()) format = ext[Ext]; diff --git a/src/Mod/Mesh/Gui/Makefile.am b/src/Mod/Mesh/Gui/Makefile.am index 82cde54ee..7bc944804 100644 --- a/src/Mod/Mesh/Gui/Makefile.am +++ b/src/Mod/Mesh/Gui/Makefile.am @@ -66,7 +66,7 @@ libMeshGui_la_CPPFLAGS = -DMeshExport= -DMeshGuiExport= libMeshGui_la_LIBADD = \ @BOOST_SIGNALS_LIB@ @BOOST_SYSTEM_LIB@ \ - @GL_LIBS@ \ + @GL_LIBS@ @ZIPIOS_LIB@ \ -lFreeCADBase \ -lFreeCADApp \ -lFreeCADGui \ diff --git a/src/Mod/Mesh/Gui/ViewProvider.cpp b/src/Mod/Mesh/Gui/ViewProvider.cpp index db7e99057..d92766190 100644 --- a/src/Mod/Mesh/Gui/ViewProvider.cpp +++ b/src/Mod/Mesh/Gui/ViewProvider.cpp @@ -27,6 +27,8 @@ # include # include # include +# include +# include # include # include # include @@ -44,6 +46,7 @@ # include # include # include +# include #endif /// Here the FreeCAD includes sorted by Base,App,Gui...... @@ -63,6 +66,7 @@ #include #include #include +#include #include #include #include @@ -82,6 +86,7 @@ #include #include #include +#include #include "ViewProvider.h" #include "SoFCIndexedFaceSet.h" @@ -484,6 +489,69 @@ std::vector ViewProviderMesh::getDisplayModes(void) const return StrList; } +bool ViewProviderMesh::exportToVrml(const char* filename, const MeshCore::Material& mat, bool binary) const +{ + SoCoordinate3* coords = new SoCoordinate3(); + SoIndexedFaceSet* faces = new SoIndexedFaceSet(); + ViewProviderMeshBuilder builder; + builder.createMesh(&static_cast(pcObject)->Mesh, coords, faces); + + SoMaterialBinding* binding = new SoMaterialBinding; + SoMaterial* material = new SoMaterial; + + if (mat.diffuseColor.size() == coords->point.getNum()) { + binding->value = SoMaterialBinding::PER_VERTEX_INDEXED; + } + else if (mat.diffuseColor.size() == faces->coordIndex.getNum()/4) { + binding->value = SoMaterialBinding::PER_FACE_INDEXED; + } + + if (mat.diffuseColor.size() > 1) { + material->diffuseColor.setNum(mat.diffuseColor.size()); + SbColor* colors = material->diffuseColor.startEditing(); + for (unsigned int i=0; idiffuseColor.finishEditing(); + } + + SoGroup* group = new SoGroup(); + group->addChild(material); + group->addChild(binding); + group->addChild(new SoTransform()); + group->addChild(coords); + group->addChild(faces); + + SoToVRML2Action tovrml2; + group->ref(); + tovrml2.apply(group); + group->unref(); + SoVRMLGroup *vrmlRoot = tovrml2.getVRML2SceneGraph(); + vrmlRoot->ref(); + std::string buffer = Gui::SoFCDB::writeNodesToString(vrmlRoot); + vrmlRoot->unref(); // release the memory as soon as possible + + Base::FileInfo fi(filename); + if (binary) { + Base::ofstream str(fi, std::ios::out | std::ios::binary); + zipios::GZIPOutputStream gzip(str); + if (gzip) { + gzip << buffer; + gzip.close(); + return true; + } + } + else { + Base::ofstream str(fi, std::ios::out); + if (str) { + str << buffer; + str.close(); + return true; + } + } + + return false; +} + bool ViewProviderMesh::setEdit(int ModNum) { if (ModNum == ViewProvider::Transform) @@ -1045,13 +1113,7 @@ void ViewProviderMesh::cutMesh(const std::vector& picked, // Get the facet indices inside the tool mesh std::vector indices; getFacetsFromPolygon(picked, Viewer, inner, indices); - - // Get the attached mesh property - Mesh::PropertyMeshKernel& meshProp = static_cast(pcObject)->Mesh; - - //Remove the facets from the mesh and open a transaction object for the undo/redo stuff - meshProp.deleteFacetIndices(indices); - pcObject->purgeTouched(); + removeFacets(indices); } void ViewProviderMesh::trimMesh(const std::vector& polygon, @@ -1137,7 +1199,7 @@ void ViewProviderMesh::splitMesh(const MeshCore::MeshKernel& toolMesh, const Bas // Remove the facets from the mesh and create a new one Mesh::MeshObject* kernel = meshProp.getValue().meshFromSegment(indices); - meshProp.deleteFacetIndices(indices); + removeFacets(indices); Mesh::Feature* splitMesh = static_cast(App::GetApplication().getActiveDocument() ->addObject("Mesh::Feature",pcObject->getNameInDocument())); // Note: deletes also kernel @@ -1167,7 +1229,9 @@ void ViewProviderMesh::segmentMesh(const MeshCore::MeshKernel& toolMesh, const B indices = complementary; } - meshProp.createSegment(indices); + Mesh::MeshObject* kernel = meshProp.startEditing(); + kernel->addSegment(indices); + meshProp.finishEditing(); static_cast(pcObject)->purgeTouched(); } @@ -1401,10 +1465,23 @@ void ViewProviderMesh::fillHole(unsigned long uFacet) //add the facets to the mesh and open a transaction object for the undo/redo stuff Gui::Application::Instance->activeDocument()->openCommand("Fill hole"); - fea->Mesh.append(newFacets, newPoints); + Mesh::MeshObject* kernel = fea->Mesh.startEditing(); + kernel->addFacets(newFacets, newPoints); + fea->Mesh.finishEditing(); Gui::Application::Instance->activeDocument()->commitCommand(); } +void ViewProviderMesh::removeFacets(const std::vector& facets) +{ + // Get the attached mesh property + Mesh::PropertyMeshKernel& meshProp = static_cast(pcObject)->Mesh; + Mesh::MeshObject* kernel = meshProp.startEditing(); + //Remove the facets from the mesh and open a transaction object for the undo/redo stuff + kernel->deleteFacets(facets); + meshProp.finishEditing(); + pcObject->purgeTouched(); +} + void ViewProviderMesh::selectFacet(unsigned long facet) { std::vector selection; diff --git a/src/Mod/Mesh/Gui/ViewProvider.h b/src/Mod/Mesh/Gui/ViewProvider.h index ce0de6b8c..3bf180bdd 100644 --- a/src/Mod/Mesh/Gui/ViewProvider.h +++ b/src/Mod/Mesh/Gui/ViewProvider.h @@ -60,6 +60,7 @@ namespace Gui { namespace MeshCore { class MeshKernel; + struct Material; } @@ -122,6 +123,7 @@ public: virtual void setDisplayMode(const char* ModeName); /// returns a list of all possible modes virtual std::vector getDisplayModes(void) const; + bool exportToVrml(const char* filename, const MeshCore::Material&, bool binary=false) const; /** @name Editing */ //@{ @@ -141,6 +143,7 @@ public: std::vector getFacetsOfRegion(const SbViewportRegion&, const SbViewportRegion&, SoCamera*) const; std::vector getVisibleFacetsAfterZoom(const SbBox2s&, const SbViewportRegion&, SoCamera*) const; std::vector getVisibleFacets(const SbViewportRegion&, SoCamera*) const; + virtual void removeFacets(const std::vector&); //@} protected: From 2e062ab79713607566248a1e480b8921d5a03b58 Mon Sep 17 00:00:00 2001 From: wmayer Date: Sun, 25 Mar 2012 13:38:32 +0200 Subject: [PATCH 5/6] 0000652: Polish language not available even if translation is available in source --- src/Gui/Language/Makefile.am | 2 ++ src/Gui/Language/Translator.cpp | 1 + src/Gui/Language/translation.qrc | 1 + src/Mod/Arch/Resources/Arch.qrc | 1 + src/Mod/Complete/Gui/Resources/Complete.qrc | 1 + src/Mod/Complete/Gui/Resources/Makefile.am | 2 ++ src/Mod/Draft/Makefile.am | 2 ++ src/Mod/Draft/Resources/Draft.qrc | 1 + src/Mod/Drawing/Gui/Resources/Drawing.qrc | 1 + src/Mod/Drawing/Gui/Resources/Makefile.am | 2 ++ src/Mod/Fem/Gui/Resources/Fem.qrc | 1 + src/Mod/Fem/Gui/Resources/Makefile.am | 2 ++ src/Mod/Image/Gui/Makefile.am | 2 ++ src/Mod/Image/Gui/Resources/Image.qrc | 1 + src/Mod/Mesh/Gui/Makefile.am | 2 ++ src/Mod/Mesh/Gui/Resources/Mesh.qrc | 1 + src/Mod/MeshPart/Gui/Resources/Makefile.am | 2 ++ src/Mod/MeshPart/Gui/Resources/MeshPart.qrc | 1 + src/Mod/Part/Gui/Makefile.am | 2 ++ src/Mod/Part/Gui/Resources/Part.qrc | 1 + src/Mod/PartDesign/Gui/Resources/Makefile.am | 2 ++ .../PartDesign/Gui/Resources/PartDesign.qrc | 1 + src/Mod/Points/Gui/Makefile.am | 2 ++ src/Mod/Points/Gui/Resources/Points.qrc | 1 + src/Mod/Raytracing/Gui/Makefile.am | 2 ++ .../Raytracing/Gui/Resources/Raytracing.qrc | 1 + .../Gui/Resources/Makefile.am | 2 ++ .../Gui/Resources/ReverseEngineering.qrc | 1 + src/Mod/Robot/Gui/Resources/Makefile.am | 2 ++ src/Mod/Robot/Gui/Resources/Robot.qrc | 1 + src/Mod/Sketcher/Gui/Resources/Makefile.am | 2 ++ src/Mod/Sketcher/Gui/Resources/Sketcher.qrc | 1 + src/Mod/Start/Gui/Resources/Start.qrc | 1 + src/Mod/Test/Gui/Makefile.am | 32 ++++++++++++++++--- src/Mod/Test/Gui/Resources/Test.qrc | 12 +++++++ 35 files changed, 88 insertions(+), 4 deletions(-) diff --git a/src/Gui/Language/Makefile.am b/src/Gui/Language/Makefile.am index aec3aeb8a..a72ca473f 100644 --- a/src/Gui/Language/Makefile.am +++ b/src/Gui/Language/Makefile.am @@ -23,6 +23,7 @@ EXTRA_DIST = \ FreeCAD_it.qm \ FreeCAD_nl.qm \ FreeCAD_no.qm \ + FreeCAD_pl.qm \ FreeCAD_pt.qm \ FreeCAD_ru.qm \ FreeCAD_se.qm \ @@ -37,6 +38,7 @@ EXTRA_DIST = \ FreeCAD_it.ts \ FreeCAD_nl.ts \ FreeCAD_no.ts \ + FreeCAD_pl.ts \ FreeCAD_pt.ts \ FreeCAD_ru.ts \ FreeCAD_se.ts \ diff --git a/src/Gui/Language/Translator.cpp b/src/Gui/Language/Translator.cpp index 9f322afd8..b32401875 100644 --- a/src/Gui/Language/Translator.cpp +++ b/src/Gui/Language/Translator.cpp @@ -146,6 +146,7 @@ Translator::Translator() d->mapLanguageTopLevelDomain[QT_TR_NOOP("Ukrainian" )] = "uk"; d->mapLanguageTopLevelDomain[QT_TR_NOOP("Finnish" )] = "fi"; d->mapLanguageTopLevelDomain[QT_TR_NOOP("Croatian" )] = "hr"; + d->mapLanguageTopLevelDomain[QT_TR_NOOP("Polish" )] = "pl"; d->activatedLanguage = "English"; d->paths = directories(); diff --git a/src/Gui/Language/translation.qrc b/src/Gui/Language/translation.qrc index 63d2e5d68..e2e81ad1e 100644 --- a/src/Gui/Language/translation.qrc +++ b/src/Gui/Language/translation.qrc @@ -9,6 +9,7 @@ FreeCAD_it.qm FreeCAD_nl.qm FreeCAD_no.qm + FreeCAD_pl.qm FreeCAD_pt.qm FreeCAD_ru.qm FreeCAD_se.qm diff --git a/src/Mod/Arch/Resources/Arch.qrc b/src/Mod/Arch/Resources/Arch.qrc index ba886872b..7d305d710 100644 --- a/src/Mod/Arch/Resources/Arch.qrc +++ b/src/Mod/Arch/Resources/Arch.qrc @@ -36,6 +36,7 @@ translations/Arch_ru.qm translations/Arch_se.qm translations/Arch_uk.qm + translations/Arch_pl.qm translations/Arch_pt.qm translations/Arch_hr.qm translations/Arch_zh.qm diff --git a/src/Mod/Complete/Gui/Resources/Complete.qrc b/src/Mod/Complete/Gui/Resources/Complete.qrc index d7115bce7..97769440c 100644 --- a/src/Mod/Complete/Gui/Resources/Complete.qrc +++ b/src/Mod/Complete/Gui/Resources/Complete.qrc @@ -9,6 +9,7 @@ translations/Complete_it.qm translations/Complete_nl.qm translations/Complete_no.qm + translations/Complete_pl.qm translations/Complete_pt.qm translations/Complete_ru.qm translations/Complete_se.qm diff --git a/src/Mod/Complete/Gui/Resources/Makefile.am b/src/Mod/Complete/Gui/Resources/Makefile.am index c895368ee..6cfd345e7 100644 --- a/src/Mod/Complete/Gui/Resources/Makefile.am +++ b/src/Mod/Complete/Gui/Resources/Makefile.am @@ -16,6 +16,7 @@ EXTRA_DIST = \ translations/Complete_it.qm \ translations/Complete_nl.qm \ translations/Complete_no.qm \ + translations/Complete_pl.qm \ translations/Complete_pt.qm \ translations/Complete_ru.qm \ translations/Complete_se.qm \ @@ -30,6 +31,7 @@ EXTRA_DIST = \ translations/Complete_it.ts \ translations/Complete_nl.ts \ translations/Complete_no.ts \ + translations/Complete_pl.ts \ translations/Complete_pt.ts \ translations/Complete_ru.ts \ translations/Complete_se.ts \ diff --git a/src/Mod/Draft/Makefile.am b/src/Mod/Draft/Makefile.am index 7cf2d4224..fef1303c4 100644 --- a/src/Mod/Draft/Makefile.am +++ b/src/Mod/Draft/Makefile.am @@ -57,6 +57,8 @@ EXTRA_DIST = \ Resources/translations/Draft_nl.qm \ Resources/translations/Draft_no.ts \ Resources/translations/Draft_no.qm \ + Resources/translations/Draft_pl.ts \ + Resources/translations/Draft_pl.qm \ Resources/translations/Draft_pt.ts \ Resources/translations/Draft_pt.qm \ Resources/translations/Draft_ru.ts \ diff --git a/src/Mod/Draft/Resources/Draft.qrc b/src/Mod/Draft/Resources/Draft.qrc index 1d9788cce..5dfc9edfd 100644 --- a/src/Mod/Draft/Resources/Draft.qrc +++ b/src/Mod/Draft/Resources/Draft.qrc @@ -68,6 +68,7 @@ translations/Draft_ru.qm translations/Draft_se.qm translations/Draft_uk.qm + translations/Draft_pl.qm translations/Draft_pt.qm translations/Draft_hr.qm translations/Draft_zh.qm diff --git a/src/Mod/Drawing/Gui/Resources/Drawing.qrc b/src/Mod/Drawing/Gui/Resources/Drawing.qrc index 853d6aa5e..5d5d80ca3 100644 --- a/src/Mod/Drawing/Gui/Resources/Drawing.qrc +++ b/src/Mod/Drawing/Gui/Resources/Drawing.qrc @@ -25,6 +25,7 @@ translations/Drawing_it.qm translations/Drawing_nl.qm translations/Drawing_no.qm + translations/Drawing_pl.qm translations/Drawing_pt.qm translations/Drawing_ru.qm translations/Drawing_se.qm diff --git a/src/Mod/Drawing/Gui/Resources/Makefile.am b/src/Mod/Drawing/Gui/Resources/Makefile.am index dbca09f2e..a6063f8ea 100644 --- a/src/Mod/Drawing/Gui/Resources/Makefile.am +++ b/src/Mod/Drawing/Gui/Resources/Makefile.am @@ -32,6 +32,7 @@ EXTRA_DIST = \ translations/Drawing_it.qm \ translations/Drawing_nl.qm \ translations/Drawing_no.qm \ + translations/Drawing_pl.qm \ translations/Drawing_pt.qm \ translations/Drawing_ru.qm \ translations/Drawing_se.qm \ @@ -46,6 +47,7 @@ EXTRA_DIST = \ translations/Drawing_it.ts \ translations/Drawing_nl.ts \ translations/Drawing_no.ts \ + translations/Drawing_pl.ts \ translations/Drawing_pt.ts \ translations/Drawing_ru.ts \ translations/Drawing_se.ts \ diff --git a/src/Mod/Fem/Gui/Resources/Fem.qrc b/src/Mod/Fem/Gui/Resources/Fem.qrc index 660112d80..db072a5bf 100644 --- a/src/Mod/Fem/Gui/Resources/Fem.qrc +++ b/src/Mod/Fem/Gui/Resources/Fem.qrc @@ -10,6 +10,7 @@ translations/Fem_it.qm translations/Fem_nl.qm translations/Fem_no.qm + translations/Fem_pl.qm translations/Fem_pt.qm translations/Fem_ru.qm translations/Fem_se.qm diff --git a/src/Mod/Fem/Gui/Resources/Makefile.am b/src/Mod/Fem/Gui/Resources/Makefile.am index f915bc77e..742affb81 100644 --- a/src/Mod/Fem/Gui/Resources/Makefile.am +++ b/src/Mod/Fem/Gui/Resources/Makefile.am @@ -26,6 +26,8 @@ EXTRA_DIST = \ translations/Fem_nl.ts \ translations/Fem_no.qm \ translations/Fem_no.ts \ + translations/Fem_pl.qm \ + translations/Fem_pl.ts \ translations/Fem_pt.qm \ translations/Fem_pt.ts \ translations/Fem_ru.qm \ diff --git a/src/Mod/Image/Gui/Makefile.am b/src/Mod/Image/Gui/Makefile.am index 0d09c514a..b24c50a5c 100644 --- a/src/Mod/Image/Gui/Makefile.am +++ b/src/Mod/Image/Gui/Makefile.am @@ -107,6 +107,8 @@ EXTRA_DIST = \ Resources/translations/Image_nl.ts \ Resources/translations/Image_no.qm \ Resources/translations/Image_no.ts \ + Resources/translations/Image_pl.qm \ + Resources/translations/Image_pl.ts \ Resources/translations/Image_pt.qm \ Resources/translations/Image_pt.ts \ Resources/translations/Image_ru.qm \ diff --git a/src/Mod/Image/Gui/Resources/Image.qrc b/src/Mod/Image/Gui/Resources/Image.qrc index fd16dcdfa..41122d6b2 100644 --- a/src/Mod/Image/Gui/Resources/Image.qrc +++ b/src/Mod/Image/Gui/Resources/Image.qrc @@ -10,6 +10,7 @@ translations/Image_it.qm translations/Image_nl.qm translations/Image_no.qm + translations/Image_pl.qm translations/Image_pt.qm translations/Image_ru.qm translations/Image_se.qm diff --git a/src/Mod/Mesh/Gui/Makefile.am b/src/Mod/Mesh/Gui/Makefile.am index 7bc944804..6b2066ff0 100644 --- a/src/Mod/Mesh/Gui/Makefile.am +++ b/src/Mod/Mesh/Gui/Makefile.am @@ -146,6 +146,8 @@ EXTRA_DIST = \ Resources/translations/Mesh_nl.ts \ Resources/translations/Mesh_no.qm \ Resources/translations/Mesh_no.ts \ + Resources/translations/Mesh_pl.qm \ + Resources/translations/Mesh_pl.ts \ Resources/translations/Mesh_pt.qm \ Resources/translations/Mesh_pt.ts \ Resources/translations/Mesh_ru.qm \ diff --git a/src/Mod/Mesh/Gui/Resources/Mesh.qrc b/src/Mod/Mesh/Gui/Resources/Mesh.qrc index 347f3b8aa..940c6d440 100644 --- a/src/Mod/Mesh/Gui/Resources/Mesh.qrc +++ b/src/Mod/Mesh/Gui/Resources/Mesh.qrc @@ -12,6 +12,7 @@ translations/Mesh_it.qm translations/Mesh_nl.qm translations/Mesh_no.qm + translations/Mesh_pl.qm translations/Mesh_pt.qm translations/Mesh_ru.qm translations/Mesh_se.qm diff --git a/src/Mod/MeshPart/Gui/Resources/Makefile.am b/src/Mod/MeshPart/Gui/Resources/Makefile.am index cbc6560bb..15086a83a 100644 --- a/src/Mod/MeshPart/Gui/Resources/Makefile.am +++ b/src/Mod/MeshPart/Gui/Resources/Makefile.am @@ -26,6 +26,8 @@ EXTRA_DIST = \ translations/MeshPart_nl.ts \ translations/MeshPart_no.qm \ translations/MeshPart_no.ts \ + translations/MeshPart_pl.qm \ + translations/MeshPart_pl.ts \ translations/MeshPart_pt.qm \ translations/MeshPart_pt.ts \ translations/MeshPart_ru.qm \ diff --git a/src/Mod/MeshPart/Gui/Resources/MeshPart.qrc b/src/Mod/MeshPart/Gui/Resources/MeshPart.qrc index 486d2d5be..2975b1730 100644 --- a/src/Mod/MeshPart/Gui/Resources/MeshPart.qrc +++ b/src/Mod/MeshPart/Gui/Resources/MeshPart.qrc @@ -10,6 +10,7 @@ translations/MeshPart_it.qm translations/MeshPart_nl.qm translations/MeshPart_no.qm + translations/MeshPart_pl.qm translations/MeshPart_pt.qm translations/MeshPart_ru.qm translations/MeshPart_se.qm diff --git a/src/Mod/Part/Gui/Makefile.am b/src/Mod/Part/Gui/Makefile.am index fe7d7a8dd..ca433d86f 100644 --- a/src/Mod/Part/Gui/Makefile.am +++ b/src/Mod/Part/Gui/Makefile.am @@ -247,6 +247,8 @@ EXTRA_DIST = \ Resources/translations/Part_nl.ts \ Resources/translations/Part_no.qm \ Resources/translations/Part_no.ts \ + Resources/translations/Part_pl.qm \ + Resources/translations/Part_pl.ts \ Resources/translations/Part_pt.qm \ Resources/translations/Part_pt.ts \ Resources/translations/Part_ru.qm \ diff --git a/src/Mod/Part/Gui/Resources/Part.qrc b/src/Mod/Part/Gui/Resources/Part.qrc index 213e2c47a..82c60f77a 100644 --- a/src/Mod/Part/Gui/Resources/Part.qrc +++ b/src/Mod/Part/Gui/Resources/Part.qrc @@ -36,6 +36,7 @@ translations/Part_it.qm translations/Part_nl.qm translations/Part_no.qm + translations/Part_pl.qm translations/Part_pt.qm translations/Part_ru.qm translations/Part_se.qm diff --git a/src/Mod/PartDesign/Gui/Resources/Makefile.am b/src/Mod/PartDesign/Gui/Resources/Makefile.am index ab021d8df..332007335 100644 --- a/src/Mod/PartDesign/Gui/Resources/Makefile.am +++ b/src/Mod/PartDesign/Gui/Resources/Makefile.am @@ -25,6 +25,8 @@ EXTRA_DIST = \ translations/PartDesign_nl.ts \ translations/PartDesign_no.qm \ translations/PartDesign_no.ts \ + translations/PartDesign_pl.qm \ + translations/PartDesign_pl.ts \ translations/PartDesign_pt.qm \ translations/PartDesign_pt.ts \ translations/PartDesign_ru.qm \ diff --git a/src/Mod/PartDesign/Gui/Resources/PartDesign.qrc b/src/Mod/PartDesign/Gui/Resources/PartDesign.qrc index 457ff1719..caff25cab 100644 --- a/src/Mod/PartDesign/Gui/Resources/PartDesign.qrc +++ b/src/Mod/PartDesign/Gui/Resources/PartDesign.qrc @@ -12,6 +12,7 @@ translations/PartDesign_it.qm translations/PartDesign_nl.qm translations/PartDesign_no.qm + translations/PartDesign_pl.qm translations/PartDesign_pt.qm translations/PartDesign_ru.qm translations/PartDesign_se.qm diff --git a/src/Mod/Points/Gui/Makefile.am b/src/Mod/Points/Gui/Makefile.am index bf7db853d..240f52679 100644 --- a/src/Mod/Points/Gui/Makefile.am +++ b/src/Mod/Points/Gui/Makefile.am @@ -100,6 +100,8 @@ EXTRA_DIST = \ Resources/translations/Points_nl.ts \ Resources/translations/Points_no.qm \ Resources/translations/Points_no.ts \ + Resources/translations/Points_pl.qm \ + Resources/translations/Points_pl.ts \ Resources/translations/Points_pt.qm \ Resources/translations/Points_pt.ts \ Resources/translations/Points_ru.qm \ diff --git a/src/Mod/Points/Gui/Resources/Points.qrc b/src/Mod/Points/Gui/Resources/Points.qrc index f58165733..b69922e70 100644 --- a/src/Mod/Points/Gui/Resources/Points.qrc +++ b/src/Mod/Points/Gui/Resources/Points.qrc @@ -9,6 +9,7 @@ translations/Points_it.qm translations/Points_nl.qm translations/Points_no.qm + translations/Points_pl.qm translations/Points_pt.qm translations/Points_ru.qm translations/Points_se.qm diff --git a/src/Mod/Raytracing/Gui/Makefile.am b/src/Mod/Raytracing/Gui/Makefile.am index e6de6088f..b83c79855 100644 --- a/src/Mod/Raytracing/Gui/Makefile.am +++ b/src/Mod/Raytracing/Gui/Makefile.am @@ -118,6 +118,8 @@ EXTRA_DIST = \ Resources/translations/Raytracing_nl.ts \ Resources/translations/Raytracing_no.qm \ Resources/translations/Raytracing_no.ts \ + Resources/translations/Raytracing_pl.qm \ + Resources/translations/Raytracing_pl.ts \ Resources/translations/Raytracing_pt.qm \ Resources/translations/Raytracing_pt.ts \ Resources/translations/Raytracing_ru.qm \ diff --git a/src/Mod/Raytracing/Gui/Resources/Raytracing.qrc b/src/Mod/Raytracing/Gui/Resources/Raytracing.qrc index a7420fd6c..69d152366 100644 --- a/src/Mod/Raytracing/Gui/Resources/Raytracing.qrc +++ b/src/Mod/Raytracing/Gui/Resources/Raytracing.qrc @@ -16,6 +16,7 @@ translations/Raytracing_it.qm translations/Raytracing_nl.qm translations/Raytracing_no.qm + translations/Raytracing_pl.qm translations/Raytracing_pt.qm translations/Raytracing_ru.qm translations/Raytracing_se.qm diff --git a/src/Mod/ReverseEngineering/Gui/Resources/Makefile.am b/src/Mod/ReverseEngineering/Gui/Resources/Makefile.am index 24b8a7852..a22aca9c0 100644 --- a/src/Mod/ReverseEngineering/Gui/Resources/Makefile.am +++ b/src/Mod/ReverseEngineering/Gui/Resources/Makefile.am @@ -26,6 +26,8 @@ EXTRA_DIST = \ translations/ReverseEngineering_nl.ts \ translations/ReverseEngineering_no.qm \ translations/ReverseEngineering_no.ts \ + translations/ReverseEngineering_pl.qm \ + translations/ReverseEngineering_pl.ts \ translations/ReverseEngineering_pt.qm \ translations/ReverseEngineering_pt.ts \ translations/ReverseEngineering_ru.qm \ diff --git a/src/Mod/ReverseEngineering/Gui/Resources/ReverseEngineering.qrc b/src/Mod/ReverseEngineering/Gui/Resources/ReverseEngineering.qrc index 93af7ddc1..5063d5c72 100644 --- a/src/Mod/ReverseEngineering/Gui/Resources/ReverseEngineering.qrc +++ b/src/Mod/ReverseEngineering/Gui/Resources/ReverseEngineering.qrc @@ -10,6 +10,7 @@ translations/ReverseEngineering_it.qm translations/ReverseEngineering_nl.qm translations/ReverseEngineering_no.qm + translations/ReverseEngineering_pl.qm translations/ReverseEngineering_pt.qm translations/ReverseEngineering_ru.qm translations/ReverseEngineering_se.qm diff --git a/src/Mod/Robot/Gui/Resources/Makefile.am b/src/Mod/Robot/Gui/Resources/Makefile.am index 14c5cfa1c..8b536ce97 100644 --- a/src/Mod/Robot/Gui/Resources/Makefile.am +++ b/src/Mod/Robot/Gui/Resources/Makefile.am @@ -38,6 +38,8 @@ EXTRA_DIST = \ translations/Robot_nl.ts \ translations/Robot_no.qm \ translations/Robot_no.ts \ + translations/Robot_pl.qm \ + translations/Robot_pl.ts \ translations/Robot_pt.qm \ translations/Robot_pt.ts \ translations/Robot_ru.qm \ diff --git a/src/Mod/Robot/Gui/Resources/Robot.qrc b/src/Mod/Robot/Gui/Resources/Robot.qrc index 97016da49..e7842fc4f 100644 --- a/src/Mod/Robot/Gui/Resources/Robot.qrc +++ b/src/Mod/Robot/Gui/Resources/Robot.qrc @@ -22,6 +22,7 @@ translations/Robot_it.qm translations/Robot_nl.qm translations/Robot_no.qm + translations/Robot_pl.qm translations/Robot_pt.qm translations/Robot_ru.qm translations/Robot_se.qm diff --git a/src/Mod/Sketcher/Gui/Resources/Makefile.am b/src/Mod/Sketcher/Gui/Resources/Makefile.am index 9f2fcbe47..1209d54ef 100644 --- a/src/Mod/Sketcher/Gui/Resources/Makefile.am +++ b/src/Mod/Sketcher/Gui/Resources/Makefile.am @@ -92,6 +92,8 @@ icons/Constraint_PointOnObject.svg \ translations/Sketcher_nl.ts \ translations/Sketcher_no.qm \ translations/Sketcher_no.ts \ + translations/Sketcher_pl.qm \ + translations/Sketcher_pl.ts \ translations/Sketcher_pt.qm \ translations/Sketcher_pt.ts \ translations/Sketcher_ru.qm \ diff --git a/src/Mod/Sketcher/Gui/Resources/Sketcher.qrc b/src/Mod/Sketcher/Gui/Resources/Sketcher.qrc index 8a3fe9324..bdc5ad805 100644 --- a/src/Mod/Sketcher/Gui/Resources/Sketcher.qrc +++ b/src/Mod/Sketcher/Gui/Resources/Sketcher.qrc @@ -74,6 +74,7 @@ translations/Sketcher_it.qm translations/Sketcher_nl.qm translations/Sketcher_no.qm + translations/Sketcher_pl.qm translations/Sketcher_pt.qm translations/Sketcher_ru.qm translations/Sketcher_se.qm diff --git a/src/Mod/Start/Gui/Resources/Start.qrc b/src/Mod/Start/Gui/Resources/Start.qrc index c709e8da3..925ecd7f9 100644 --- a/src/Mod/Start/Gui/Resources/Start.qrc +++ b/src/Mod/Start/Gui/Resources/Start.qrc @@ -11,6 +11,7 @@ translations/StartPage_ru.qm translations/StartPage_se.qm translations/StartPage_uk.qm + translations/StartPage_pl.qm translations/StartPage_pt.qm translations/StartPage_hr.qm translations/StartPage_zh.qm diff --git a/src/Mod/Test/Gui/Makefile.am b/src/Mod/Test/Gui/Makefile.am index 8a3ead943..35ce4cd52 100644 --- a/src/Mod/Test/Gui/Makefile.am +++ b/src/Mod/Test/Gui/Makefile.am @@ -77,14 +77,38 @@ EXTRA_DIST = \ CMakeLists.txt \ UnitTest.ui \ Resources/Test.qrc \ + Resources/translations/Test_af.qm \ + Resources/translations/Test_af.ts \ Resources/translations/Test_de.qm \ - Resources/translations/Test_es.qm \ - Resources/translations/Test_fr.qm \ - Resources/translations/Test_it.qm \ - Resources/translations/Test_se.qm \ Resources/translations/Test_de.ts \ + Resources/translations/Test_es.qm \ Resources/translations/Test_es.ts \ + Resources/translations/Test_fi.qm \ + Resources/translations/Test_fi.ts \ + Resources/translations/Test_fr.qm \ Resources/translations/Test_fr.ts \ + Resources/translations/Test_hr.qm \ + Resources/translations/Test_hr.ts \ + Resources/translations/Test_hu.qm \ + Resources/translations/Test_hu.ts \ + Resources/translations/Test_it.qm \ Resources/translations/Test_it.ts \ + Resources/translations/Test_ja.qm \ + Resources/translations/Test_ja.ts \ + Resources/translations/Test_nl.qm \ + Resources/translations/Test_nl.ts \ + Resources/translations/Test_no.qm \ + Resources/translations/Test_no.ts \ + Resources/translations/Test_pl.qm \ + Resources/translations/Test_pl.ts \ + Resources/translations/Test_pt.qm \ + Resources/translations/Test_pt.ts \ + Resources/translations/Test_ru.qm \ + Resources/translations/Test_ru.ts \ + Resources/translations/Test_se.qm \ Resources/translations/Test_se.ts \ + Resources/translations/Test_uk.qm \ + Resources/translations/Test_uk.ts \ + Resources/translations/Test_zh.qm \ + Resources/translations/Test_zh.ts \ qtunittest.py diff --git a/src/Mod/Test/Gui/Resources/Test.qrc b/src/Mod/Test/Gui/Resources/Test.qrc index ef40be4f0..a494fcc5b 100644 --- a/src/Mod/Test/Gui/Resources/Test.qrc +++ b/src/Mod/Test/Gui/Resources/Test.qrc @@ -1,9 +1,21 @@ + translations/Test_af.qm translations/Test_de.qm translations/Test_es.qm + translations/Test_fi.qm translations/Test_fr.qm + translations/Test_hr.qm + translations/Test_hu.qm translations/Test_it.qm + translations/Test_ja.qm + translations/Test_nl.qm + translations/Test_no.qm + translations/Test_pl.qm + translations/Test_pt.qm + translations/Test_ru.qm translations/Test_se.qm + translations/Test_uk.qm + translations/Test_zh.qm From 0f6d6d4b3735573e4a14df5d40b48c7314ca2f26 Mon Sep 17 00:00:00 2001 From: wmayer Date: Mon, 26 Mar 2012 15:54:13 +0200 Subject: [PATCH 6/6] Implement manual alignment utility --- src/Gui/Application.cpp | 1 + src/Gui/CMakeLists.txt | 7 +- src/Gui/CommandDoc.cpp | 60 ++ src/Gui/ManualAlignment.cpp | 1244 ++++++++++++++++++++++++++++ src/Gui/ManualAlignment.h | 257 ++++++ src/Gui/SoAxisCrossKit.cpp | 146 +++- src/Gui/SoAxisCrossKit.h | 29 + src/Gui/SoFCDB.cpp | 1 + src/Gui/SplitView3DInventor.cpp | 102 ++- src/Gui/SplitView3DInventor.h | 23 +- src/Gui/Workbench.cpp | 3 +- src/Mod/Complete/Gui/Workbench.cpp | 3 +- 12 files changed, 1822 insertions(+), 54 deletions(-) create mode 100644 src/Gui/ManualAlignment.cpp create mode 100644 src/Gui/ManualAlignment.h diff --git a/src/Gui/Application.cpp b/src/Gui/Application.cpp index deffe1024..2dbc4b2c8 100644 --- a/src/Gui/Application.cpp +++ b/src/Gui/Application.cpp @@ -1407,6 +1407,7 @@ void Application::initTypes(void) Gui::BaseView ::init(); Gui::MDIView ::init(); Gui::View3DInventor ::init(); + Gui::AbstractSplitView ::init(); Gui::SplitView3DInventor ::init(); // View Provider Gui::ViewProvider ::init(); diff --git a/src/Gui/CMakeLists.txt b/src/Gui/CMakeLists.txt index 133d81a54..b7788cfcd 100644 --- a/src/Gui/CMakeLists.txt +++ b/src/Gui/CMakeLists.txt @@ -125,6 +125,7 @@ set(Gui_MOC_HDRS HelpView.h InputVector.h MainWindow.h + ManualAlignment.h MDIView.h NetworkRetriever.h OnlineDocumentation.h @@ -627,7 +628,7 @@ SET(Inventor_CPP_SRCS SoFCInteractiveElement.cpp SoFCOffscreenRenderer.cpp SoFCSelection.cpp - SoFCUnifiedSelection.cpp + SoFCUnifiedSelection.cpp SoFCSelectionAction.cpp SoFCVectorizeSVGAction.cpp SoFCVectorizeU3DAction.cpp @@ -647,7 +648,7 @@ SET(Inventor_SRCS SoFCInteractiveElement.h SoFCOffscreenRenderer.h SoFCSelection.h - SoFCUnifiedSelection.h + SoFCUnifiedSelection.h SoFCSelectionAction.h SoFCVectorizeSVGAction.h SoFCVectorizeU3DAction.h @@ -743,6 +744,7 @@ SET(FreeCADGui_CPP_SRCS Thumbnail.cpp Utilities.cpp WaitCursor.cpp + ManualAlignment.cpp ) SET(FreeCADGui_SRCS Application.h @@ -763,6 +765,7 @@ SET(FreeCADGui_SRCS Thumbnail.h Utilities.h WaitCursor.h + ManualAlignment.h ) SET(FreeCADGui_SRCS diff --git a/src/Gui/CommandDoc.cpp b/src/Gui/CommandDoc.cpp index a0496abab..52fa870be 100644 --- a/src/Gui/CommandDoc.cpp +++ b/src/Gui/CommandDoc.cpp @@ -50,11 +50,13 @@ #include "DlgProjectUtility.h" #include "Transform.h" #include "Placement.h" +#include "ManualAlignment.h" #include "WaitCursor.h" #include "ViewProvider.h" #include #include #include "MergeDocuments.h" +#include "NavigationStyle.h" using namespace Gui; @@ -1013,6 +1015,63 @@ bool StdCmdPlacement::isActive(void) return (Gui::Control().activeDialog()==0); } +//=========================================================================== +// Std_Alignment +//=========================================================================== +DEF_STD_CMD_A(StdCmdAlignment); + +StdCmdAlignment::StdCmdAlignment() + : Command("Std_Alignment") +{ + sGroup = QT_TR_NOOP("Edit"); + sMenuText = QT_TR_NOOP("Alignment..."); + sToolTipText = QT_TR_NOOP("Align the selected objects"); + sStatusTip = QT_TR_NOOP("Align the selected objects"); + sWhatsThis = "Std_Alignment"; +} + +void StdCmdAlignment::activated(int iMsg) +{ + std::vector sel = Gui::Selection().getObjectsOfType + (App::GeoFeature::getClassTypeId()); + ManualAlignment* align = ManualAlignment::instance(); + QObject::connect(align, SIGNAL(emitCanceled()), align, SLOT(deleteLater())); + QObject::connect(align, SIGNAL(emitFinished()), align, SLOT(deleteLater())); + + // Get the fixed and moving meshes + FixedGroup fixedGroup; + std::map groupMap; + fixedGroup.addView(sel[0]); + groupMap[0].addView(sel[1]); + + // add the fixed group + align->setFixedGroup(fixedGroup); + + // create the model of movable groups + MovableGroupModel model; + model.addGroups(groupMap); + align->setModel(model); + Base::Type style = Base::Type::fromName("Gui::CADNavigationStyle"); + Gui::Document* doc = Application::Instance->activeDocument(); + if (doc) { + View3DInventor* mdi = qobject_cast(doc->getActiveView()); + if (mdi) { + style = mdi->getViewer()->navigationStyle()->getTypeId(); + } + } + + align->setMinPoints(1); + align->startAlignment(style); + Gui::Selection().clearSelection(); +} + +bool StdCmdAlignment::isActive(void) +{ + if (ManualAlignment::hasInstance()) + return false; + return Gui::Selection().countObjectsOfType(App::GeoFeature::getClassTypeId()) == 2; +} + //=========================================================================== // Std_Edit //=========================================================================== @@ -1085,6 +1144,7 @@ void CreateDocCommands(void) rcCmdMgr.addCommand(new StdCmdRefresh()); rcCmdMgr.addCommand(new StdCmdTransform()); rcCmdMgr.addCommand(new StdCmdPlacement()); + rcCmdMgr.addCommand(new StdCmdAlignment()); rcCmdMgr.addCommand(new StdCmdEdit()); } diff --git a/src/Gui/ManualAlignment.cpp b/src/Gui/ManualAlignment.cpp new file mode 100644 index 000000000..ae4d8e178 --- /dev/null +++ b/src/Gui/ManualAlignment.cpp @@ -0,0 +1,1244 @@ +/*************************************************************************** + * Copyright (c) 2012 Werner Mayer * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + + +#include "PreCompiled.h" +#ifndef _PreComp_ +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ManualAlignment.h" +#include "BitmapFactory.h" +#include "SoAxisCrossKit.h" + + +using namespace Gui; + +AlignmentGroup::AlignmentGroup() +{ +} + +AlignmentGroup::~AlignmentGroup() +{ +} + +void AlignmentGroup::addView(App::DocumentObject* pView) +{ + if (pView) { + App::Document* rDoc = pView->getDocument(); + Gui::Document* pDoc = Gui::Application::Instance->getDocument(rDoc); + Gui::ViewProviderDocumentObject* pProvider = static_cast + (pDoc->getViewProvider(pView)); + this->_views.push_back(pProvider); + } +} + +std::vector AlignmentGroup::getViews() const +{ + std::vector views; + + std::vector::const_iterator it; + for (it = this->_views.begin(); it != this->_views.end(); ++it) { + App::DocumentObject* pView = (*it)->getObject(); + views.push_back(pView); + } + + return views; +} + +bool AlignmentGroup::hasView(Gui::ViewProviderDocumentObject* pView) const +{ + std::vector::const_iterator it; + for (it = this->_views.begin(); it != this->_views.end(); ++it) { + if (*it == pView) + return true; + } + + return false; +} + +void AlignmentGroup::removeView(Gui::ViewProviderDocumentObject* pView) +{ + std::vector::iterator it; + for (it = this->_views.begin(); it != this->_views.end(); ++it) { + if (*it == pView) { + this->_views.erase(it); + break; + } + } +} + +void AlignmentGroup::addToViewer(Gui::View3DInventorViewer* viewer) const +{ + std::vector::const_iterator it; + for (it = this->_views.begin(); it != this->_views.end(); ++it) + viewer->addViewProvider(*it); + + viewer->viewAll(); +} + +void AlignmentGroup::removeFromViewer(Gui::View3DInventorViewer* viewer) const +{ + std::vector::const_iterator it; + for (it = this->_views.begin(); it != this->_views.end(); ++it) + viewer->removeViewProvider(*it); +} + +void AlignmentGroup::setRandomColor() +{ + std::vector::iterator it; + for (it = this->_views.begin(); it != this->_views.end(); ++it) { + float r = /*(float)rand()/(float)RAND_MAX*/0.0f; + float g = (float)rand()/(float)RAND_MAX; + float b = (float)rand()/(float)RAND_MAX; + if ((*it)->isDerivedFrom(Gui::ViewProviderGeometryObject::getClassTypeId())) { + SoSearchAction searchAction; + searchAction.setType(SoMaterial::getClassTypeId()); + searchAction.setInterest(SoSearchAction::FIRST); + searchAction.apply((*it)->getRoot()); + SoPath* selectionPath = searchAction.getPath(); + + if (selectionPath) { + SoMaterial* material = static_cast(selectionPath->getTail()); + material->diffuseColor.setValue(r, g, b); + } + } + } +} + +Gui::Document* AlignmentGroup::getDocument() const +{ + if (this->_views.empty()) + return 0; + App::DocumentObject* pView = this->_views[0]->getObject(); + if (pView) { + App::Document* rDoc = pView->getDocument(); + Gui::Document* pDoc = Gui::Application::Instance->getDocument(rDoc); + return pDoc; + } + + return 0; +} + +void AlignmentGroup::addPoint(const Base::Vector3d& pnt) +{ + this->_pickedPoints.push_back(pnt); +} + +void AlignmentGroup::removeLastPoint() +{ + this->_pickedPoints.pop_back(); +} + +int AlignmentGroup::countPoints() const +{ + return this->_pickedPoints.size(); +} + +const std::vector& AlignmentGroup::getPoints() const +{ + return this->_pickedPoints; +} + +void AlignmentGroup::clearPoints() +{ + this->_pickedPoints.clear(); +} + +void AlignmentGroup::setAlignable(bool align) +{ + //std::vector::iterator it; + //for (it = this->_views.begin(); it != this->_views.end(); ++it) { + // if (!align){ + // App::PropertyColor* pColor = (App::PropertyColor*)(*it)->getPropertyByName("ShapeColor"); + // if (pColor) + // pColor->touch(); // resets to color defined by property + // } + //} +} + +void AlignmentGroup::moveTo(AlignmentGroup& that) +{ + std::vector::iterator it; + for (it = this->_views.begin(); it != this->_views.end(); ++it) + that._views.push_back(*it); + + this->_views.clear(); +} + +void AlignmentGroup::clear() +{ + this->_views.clear(); + this->_pickedPoints.clear(); +} + +bool AlignmentGroup::isEmpty() const +{ + return this->_views.empty(); +} + +int AlignmentGroup::count() const +{ + return this->_views.size(); +} + +// ------------------------------------------------------------------ + +MovableGroup::MovableGroup() +{ +} + +MovableGroup::~MovableGroup() +{ +} + +// ------------------------------------------------------------------ + +FixedGroup::FixedGroup() +{ +} + +FixedGroup::~FixedGroup() +{ +} + +// ------------------------------------------------------------------ + +MovableGroupModel::MovableGroupModel() +{ +} + +MovableGroupModel::~MovableGroupModel() +{ +} + +void MovableGroupModel::addGroup(const MovableGroup& grp) +{ + this->_groups.push_back(grp); +} + +void MovableGroupModel::addGroups(const std::map& grps) +{ + for (std::map::const_iterator it = grps.begin(); it != grps.end(); ++it) + this->_groups.push_back(it->second); +} + +void MovableGroupModel::removeActiveGroup() +{ + this->_groups.erase(this->_groups.begin()); +} + +MovableGroup& MovableGroupModel::activeGroup() +{ + // Make sure that the array is not empty + if (this->_groups.empty()) + throw Base::Exception("Empty group"); + return *(this->_groups.begin()); +} + +const MovableGroup& MovableGroupModel::activeGroup() const +{ + // Make sure that the array is not empty + if (this->_groups.empty()) + throw Base::Exception("Empty group"); + return *(this->_groups.begin()); +} + +void MovableGroupModel::continueAlignment() +{ + if (!isEmpty()) + removeActiveGroup(); +} + +void MovableGroupModel::clear() +{ + this->_groups.clear(); +} + +bool MovableGroupModel::isEmpty() const +{ + return this->_groups.empty(); +} + +int MovableGroupModel::count() const +{ + return this->_groups.size(); +} + +// ------------------------------------------------------------------ + +namespace Gui { +class AlignmentView : public Gui::AbstractSplitView +{ +public: + QLabel* myLabel; + + AlignmentView(Gui::Document* pcDocument, QWidget* parent, Qt::WFlags wflags=0) + : AbstractSplitView(pcDocument, parent, wflags) + { + QSplitter* mainSplitter=0; + mainSplitter = new QSplitter(Qt::Horizontal, this); + _viewer.push_back(new View3DInventorViewer(mainSplitter)); + _viewer.push_back(new View3DInventorViewer(mainSplitter)); + + QFrame* vbox = new QFrame(this); + QVBoxLayout* layout = new QVBoxLayout(); + layout->setMargin(0); + layout->setSpacing(0); + vbox->setLayout(layout); + + myLabel = new QLabel(this); + myLabel->setAutoFillBackground(true); + QPalette pal = myLabel->palette(); + pal.setColor(QPalette::Window, Qt::darkGray); + pal.setColor(QPalette::WindowText, Qt::white); + myLabel->setPalette(pal); + mainSplitter->setPalette(pal); + myLabel->setAlignment(Qt::AlignCenter); + myLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); + QFont font = myLabel->font(); + font.setPointSize(14); + myLabel->setFont(font); + layout->addWidget(myLabel); + layout->addWidget(mainSplitter); + + vbox->show(); + setCentralWidget(vbox); + + // apply the user settings + setupSettings(); + + static_cast(getViewer(0)->getSceneManager()->getSceneGraph())-> + addChild(setupHeadUpDisplay(tr("Movable object"))); + static_cast(getViewer(1)->getSceneManager()->getSceneGraph())-> + addChild(setupHeadUpDisplay(tr("Fixed object"))); + } + ~AlignmentView() + { + } + bool canClose() + { + return false; + } + SoNode* setupHeadUpDisplay(const QString& text) const + { + SoSeparator* hudRoot = new SoSeparator; + hudRoot->ref(); + + SoOrthographicCamera* hudCam = new SoOrthographicCamera(); + hudCam->viewportMapping = SoCamera::LEAVE_ALONE; + + // Set the position in the window. + // [0, 0] is in the center of the screen. + // + SoTranslation* hudTrans = new SoTranslation; + hudTrans->translation.setValue(-0.95f, -0.95f, 0.0f); + + QFont font = this->font(); + font.setPointSize(24); + QFontMetrics fm(font); + + QColor front; + front.setRgbF(0.8f, 0.8f, 0.8f); + + int w = fm.width(text); + int h = fm.height(); + + QImage image(w,h,QImage::Format_ARGB32_Premultiplied); + image.fill(0x00000000); + QPainter painter(&image); + painter.setRenderHint(QPainter::Antialiasing); + painter.setPen(front); + painter.setFont(font); + painter.drawText(0,0,w,h,Qt::AlignLeft,text); + painter.end(); + SoSFImage sfimage; + Gui::BitmapFactory().convert(image, sfimage); + SoImage* hudImage = new SoImage(); + hudImage->image = sfimage; + + // Assemble the parts... + // + hudRoot->addChild(hudCam); + hudRoot->addChild(hudTrans); + hudRoot->addChild(hudImage); + + return hudRoot; + } +}; +} + +class ManualAlignment::Private { +public: + SoSeparator * picksepLeft; + SoSeparator * picksepRight; + SoNodeSensor* sensorCam1; + SoNodeSensor* sensorCam2; + SbRotation rot_cam1, rot_cam2; + SbVec3f pos_cam1, pos_cam2; + + Private() + : sensorCam1(0), sensorCam2(0) + { + // left view + picksepLeft = new SoSeparator; + picksepLeft->ref(); + // right view + picksepRight = new SoSeparator; + picksepRight->ref(); + } + ~Private() + { + picksepLeft->unref(); + picksepRight->unref(); + delete sensorCam1; + delete sensorCam2; + } + + static + void reorientCamera(SoCamera * cam, const SbRotation & rot) + { + if (cam == NULL) return; + + // Find global coordinates of focal point. + SbVec3f direction; + cam->orientation.getValue().multVec(SbVec3f(0, 0, -1), direction); + SbVec3f focalpoint = cam->position.getValue() + + cam->focalDistance.getValue() * direction; + + // Set new orientation value by accumulating the new rotation. + cam->orientation = rot * cam->orientation.getValue(); + + // Reposition camera so we are still pointing at the same old focal point. + cam->orientation.getValue().multVec(SbVec3f(0, 0, -1), direction); + cam->position = focalpoint - cam->focalDistance.getValue() * direction; + } + + static + void copyCameraSettings(SoCamera* cam1, SbRotation& rot_cam1, SbVec3f& pos_cam1, + SoCamera* cam2, SbRotation& rot_cam2, SbVec3f& pos_cam2) + { + // recompute the diff we have applied to the camera's orientation + SbRotation rot = cam1->orientation.getValue(); + SbRotation dif = rot * rot_cam1.inverse(); + rot_cam1 = rot; + + // copy the values + cam2->enableNotify(FALSE); + cam2->nearDistance = cam1->nearDistance; + cam2->farDistance = cam1->farDistance; + cam2->focalDistance = cam1->focalDistance; + reorientCamera(cam2,dif); + rot_cam2 = cam2->orientation.getValue(); + + // reverse engineer the translation part in wc + SbVec3f pos = cam1->position.getValue(); + SbVec3f difpos = pos - pos_cam1; + pos_cam1 = pos; + // the translation in pixel coords + cam1->orientation.getValue().inverse().multVec(difpos,difpos); + // the translation again in wc for the second camera + cam2->orientation.getValue().multVec(difpos,difpos); + cam2->position.setValue(cam2->position.getValue()+difpos); + + if (cam1->getTypeId() == cam2->getTypeId()) { + if (cam1->getTypeId() == SoOrthographicCamera::getClassTypeId()) + static_cast(cam2)->height = + static_cast(cam1)->height; + } + + cam2->enableNotify(TRUE); + } + static + void syncCameraCB(void * data, SoSensor * s) + { + ManualAlignment* self = reinterpret_cast(data); + if (!self->myViewer) + return; // already destroyed + SoCamera* cam1 = self->myViewer->getViewer(0)->getCamera(); + SoCamera* cam2 = self->myViewer->getViewer(1)->getCamera(); + if (!cam1 || !cam2) + return; // missing camera + SoNodeSensor* sensor = static_cast(s); + SoNode* node = sensor->getAttachedNode(); + if (node && node->getTypeId().isDerivedFrom(SoCamera::getClassTypeId())) { + if (node == cam1) { + Private::copyCameraSettings(cam1, self->d->rot_cam1, self->d->pos_cam1, + cam2, self->d->rot_cam2, self->d->pos_cam2); + self->myViewer->getViewer(1)->render(); + } + else if (node == cam2) { + Private::copyCameraSettings(cam2, self->d->rot_cam2, self->d->pos_cam2, + cam1, self->d->rot_cam1, self->d->pos_cam1); + self->myViewer->getViewer(0)->render(); + } + } + } + + static Base::Placement + transformation2x2(const Base::Vector3d& plane1_base, + const Base::Vector3d& plane1_xaxis, + const Base::Vector3d& plane2_base, + const Base::Vector3d& plane2_xaxis) + { + // the transformation is: + // * move from plane1_base to plane2_base + // * rotate from plane1_zaxis to plane2_zaxis around plane2_base as center point + Base::Rotation rot(plane1_xaxis, plane2_xaxis); + + Base::Vector3d pln_base; + rot.multVec(plane1_base,pln_base); + Base::Vector3d dif = plane2_base - pln_base; + return Base::Placement(dif, rot); + } + + static Base::Placement + transformation3x3(const Base::Vector3d& plane1_base, + const Base::Vector3d& plane1_zaxis, + const Base::Vector3d& plane1_xaxis, + const Base::Vector3d& plane2_base, + const Base::Vector3d& plane2_zaxis, + const Base::Vector3d& plane2_xaxis) + { + // the transformation is: + // * move from plane1_base to plane2_base + // * rotate from plane1_zaxis to plane2_zaxis around plane2_base as center point + Base::Rotation rot(plane1_zaxis, plane2_zaxis); + + // first transformation to align the plane normals and base points + Base::Vector3d dif1 = plane1_base; + rot.multVec(dif1,dif1); + dif1 = plane2_base - dif1; + Base::Placement plm1(dif1, rot); + + // second transformation to align the planes' x axes + Base::Vector3d pln_xaxis; + rot.multVec(plane1_xaxis,pln_xaxis); + Base::Rotation rot2(pln_xaxis, plane2_xaxis); + Base::Vector3d dif2 = plane2_base; + rot2.multVec(dif2,dif2); + dif2 = plane2_base - dif2; + Base::Placement plm2(dif2, rot2); + plm2 = plm2 * plm1; + return plm2; + } +}; + +/* TRANSLATOR Gui::ManualAlignment */ + +ManualAlignment* ManualAlignment::_instance = 0; + +/** + * Construction. + */ +ManualAlignment::ManualAlignment() + : myViewer(0), myDocument(0), myPickPoints(3), d(new Private) +{ + // connect with the application's signal for deletion of documents + this->connectApplicationDeletedDocument = Gui::Application::Instance->signalDeleteDocument + .connect(boost::bind(&ManualAlignment::slotDeletedDocument, this, _1)); + + // setup sensor connection + d->sensorCam1 = new SoNodeSensor(Private::syncCameraCB, this); + d->sensorCam2 = new SoNodeSensor(Private::syncCameraCB, this); +} + +/** + * Destruction. + */ +ManualAlignment::~ManualAlignment() +{ + this->connectDocumentDeletedObject.disconnect(); + this->connectApplicationDeletedDocument.disconnect(); + closeViewer(); + delete d; + _instance = 0; +} + +/** + * Creates the one and only instance of this class. + */ +ManualAlignment* ManualAlignment::instance() +{ + // not initialized? + if (!_instance) + _instance = new ManualAlignment(); + return _instance; +} + +/** + * Destructs the one and only instance of this class. + */ +void ManualAlignment::destruct() +{ + if (_instance) { + ManualAlignment* tmp = _instance; + _instance = 0; + delete tmp; + } +} + +/** + * Checks whether the one instance exists. + */ +bool ManualAlignment::hasInstance() +{ + return _instance != 0; +} + +void ManualAlignment::setMinPoints(int minPoints) +{ + if ((minPoints > 0) && (minPoints <= 3)) + myPickPoints = minPoints; +} + +void ManualAlignment::setFixedGroup(const FixedGroup& fixed) +{ + this->myFixedGroup = fixed; + this->myDocument = fixed.getDocument(); +} + +void ManualAlignment::setModel(const MovableGroupModel& model) +{ + this->myAlignModel = model; +} + +void ManualAlignment::clearAll() +{ + myFixedGroup.clear(); + myAlignModel.clear(); + myDocument = 0; +} + +void ManualAlignment::setViewingDirections(const Base::Vector3d& view1, const Base::Vector3d& up1, + const Base::Vector3d& view2, const Base::Vector3d& up2) +{ + if (myViewer.isNull()) + return; + + { + SbRotation rot; + rot.setValue(SbVec3f(0.0f, 0.0f, 1.0f), SbVec3f(-view1.x,-view1.y,-view1.z)); + + SbRotation rot2; + SbVec3f up(0.0f, 1.0f, 0.0f); + rot.multVec(up, up); + rot2.setValue(up, SbVec3f(up1.x, up1.y, up1.z)); + myViewer->getViewer(0)->getCamera()->orientation.setValue(rot * rot2); + myViewer->getViewer(0)->viewAll(); + } + + { + SbRotation rot; + rot.setValue(SbVec3f(0.0f, 0.0f, 1.0f), SbVec3f(-view2.x,-view2.y,-view2.z)); + + SbRotation rot2; + SbVec3f up(0.0f, 1.0f, 0.0f); + rot.multVec(up, up); + rot2.setValue(up, SbVec3f(up2.x, up2.y, up2.z)); + myViewer->getViewer(1)->getCamera()->orientation.setValue(rot * rot2); + myViewer->getViewer(1)->viewAll(); + } +} + +/** + * Performs the alignment for the specified aligned and non-aligned views specified by setModel() and setFixedGroup(). + */ +void ManualAlignment::startAlignment(Base::Type mousemodel) +{ + // allow only one alignment at a time + if (!myViewer.isNull()) { + QMessageBox::warning(qApp->activeWindow(), tr("Manual alignment"), tr("The alignment is already in progress.")); + return; + } + + myTransform = Base::Placement(); + + if (myFixedGroup.isEmpty()) + return; + if (myAlignModel.isEmpty()) + return; + + // create a splitted window for picking the points + myViewer = new AlignmentView(myDocument,Gui::getMainWindow()); + myViewer->setWindowTitle(tr("Alignment[*]")); + myViewer->setWindowIcon(QApplication::windowIcon()); + myViewer->resize(400, 300); + Gui::getMainWindow()->addWindow(myViewer); + myViewer->showMaximized(); + int n = this->myPickPoints; + QString msg = n == 1 + ? tr("Please, select at least one point in the left and the right view") + : tr("Please, select at least %1 points in the left and the right view").arg(n); + myViewer->myLabel->setText(msg); + + connect(myViewer, SIGNAL(destroyed()), this, SLOT(reset())); + + // show all aligned views in the 2nd view + myFixedGroup.addToViewer(myViewer->getViewer(1)); + myFixedGroup.setAlignable(true); + + // set picked points root + SoNode* node1 = myViewer->getViewer(0)->getSceneGraph(); + if (node1->getTypeId().isDerivedFrom(SoGroup::getClassTypeId())){ + ((SoGroup*)node1)->addChild(d->picksepLeft); + } + SoNode* node2 = myViewer->getViewer(1)->getSceneGraph(); + if (node2->getTypeId().isDerivedFrom(SoGroup::getClassTypeId())){ + ((SoGroup*)node2)->addChild(d->picksepRight); + } + + myViewer->getViewer(0)->setEditing(true); + myViewer->getViewer(0)->addEventCallback(SoMouseButtonEvent::getClassTypeId(), + ManualAlignment::probePickedCallback); + myViewer->getViewer(1)->setEditing(true); + myViewer->getViewer(1)->addEventCallback(SoMouseButtonEvent::getClassTypeId(), + ManualAlignment::probePickedCallback); + // apply the mouse model + myViewer->getViewer(0)->setNavigationType(mousemodel); + myViewer->getViewer(1)->setNavigationType(mousemodel); + + // Connect to the document's signal as we want to be notified when something happens + if (this->connectDocumentDeletedObject.connected()) + this->connectDocumentDeletedObject.disconnect(); + this->connectDocumentDeletedObject = myDocument->signalDeletedObject.connect(boost::bind + (&ManualAlignment::slotDeletedObject, this, _1)); + + continueAlignment(); +} + +/** + * If still one view needs to be aligned then it is shown in the first window. If all views are aligned the process will be terminated. + */ +void ManualAlignment::continueAlignment() +{ + myFixedGroup.clearPoints(); + d->picksepLeft->removeAllChildren(); + d->picksepRight->removeAllChildren(); + + if (!myAlignModel.isEmpty()) { + AlignmentGroup& grp = myAlignModel.activeGroup(); + grp.clearPoints(); + grp.addToViewer(myViewer->getViewer(0)); + grp.setAlignable(true); + + Gui::getMainWindow()->statusBar()->showMessage(tr("Please pick points in the left and right view")); + + myViewer->getViewer(0)->setEditingCursor(QCursor(Qt::PointingHandCursor)); + myViewer->getViewer(1)->setEditingCursor(QCursor(Qt::PointingHandCursor)); + } + else { + finish(); + } +} + +void ManualAlignment::closeViewer() +{ + if (!myViewer) + return; + // Close the viewer +#if !defined(NO_USE_QT_MDI_AREA) + if (myViewer->parentWidget()) + myViewer->parentWidget()->deleteLater(); +#else + myViewer->deleteLater(); +#endif + myViewer = 0; +} + +/** + * Make all views unpickable and resets internal data. + */ +void ManualAlignment::reset() +{ + if (!myAlignModel.isEmpty()) { + myAlignModel.activeGroup().setAlignable(false); + myAlignModel.activeGroup().clear(); + myAlignModel.clear(); + } + + myFixedGroup.setAlignable(false); + myFixedGroup.clear(); + + d->picksepLeft->removeAllChildren(); + d->picksepRight->removeAllChildren(); + + if (myDocument) { + this->connectDocumentDeletedObject.disconnect(); + myDocument = 0; + } +} + +/** + * Terminates the process and closes the windows. + */ +void ManualAlignment::finish() +{ + if (myViewer.isNull()) + return; + + if (myDocument) + myDocument->getDocument()->recompute(); + closeViewer(); + reset(); + + Gui::getMainWindow()->statusBar()->showMessage(tr("The alignment has finished")); + + // If an event receiver has been defined send the manual alignment finished event to it + emitFinished(); +} + +/** + * Cancels the process and clöses the windows without performing an alignment. + */ +void ManualAlignment::cancel() +{ + if (myViewer.isNull()) + return; + + closeViewer(); + myTransform = Base::Placement(); + reset(); + + Gui::getMainWindow()->statusBar()->showMessage(tr("The alignment has been canceled")); + + // If an event receiver has been defined send the manual alignment cancelled event to it + emitCanceled(); +} + +void ManualAlignment::align() +{ + // Now we can start the actual alignment + if (myAlignModel.activeGroup().countPoints() < myPickPoints) { + QMessageBox::warning(myViewer, tr("Manual alignment"), + tr("Too few points picked in the left view." + " At least %1 points are needed.").arg(myPickPoints)); + } + else if (myFixedGroup.countPoints() < myPickPoints) { + QMessageBox::warning(myViewer, tr("Manual alignment"), + tr("Too few points picked in the right view." + " At least %1 points are needed.").arg(myPickPoints)); + } + else if (myAlignModel.activeGroup().countPoints() != myFixedGroup.countPoints()) { + QMessageBox::warning(myViewer, tr("Manual alignment"), + tr("Different number of points picked in left and right view.\n" + "On the left view %1 points are picked,\n" + "on the right view %2 points are picked.") + .arg(myAlignModel.activeGroup().countPoints()) + .arg(myFixedGroup.countPoints())); + } + else { + // do not allow to pick further points + myAlignModel.activeGroup().removeFromViewer(myViewer->getViewer(0)); + myAlignModel.activeGroup().setAlignable(false); + std::vector pViews = myAlignModel.activeGroup().getViews(); + Gui::getMainWindow()->statusBar()->showMessage(tr("Try to align group of views")); + + // Compute alignment + bool ok = computeAlignment(myAlignModel.activeGroup().getPoints(), myFixedGroup.getPoints()); + if (ok) { + // Align views + for (std::vector::iterator it = pViews.begin(); it != pViews.end(); ++it) + alignObject(*it); + + // the alignment was successful so show it in the right view now + //myAlignModel.activeGroup().setRandomColor(); + myAlignModel.activeGroup().setAlignable(true); + myAlignModel.activeGroup().addToViewer(myViewer->getViewer(1)); + myAlignModel.activeGroup().moveTo(myFixedGroup); + myAlignModel.continueAlignment(); + } + else { + // Inform user that alignment failed + int ret = QMessageBox::critical(myViewer, tr("Manual alignment"), + tr("The alignment failed.\nHow do you want to proceed?"), + tr("Retry"), tr("Ignore"), tr("Abort")); + if ( ret == 1 ) { + myAlignModel.continueAlignment(); + } + else if ( ret == 2 ) { + finish(); + return; + } + } + + continueAlignment(); + } +} + +void ManualAlignment::showInstructions() +{ + // Now we can start the actual alignment + if (myAlignModel.activeGroup().countPoints() < myPickPoints) { + Gui::getMainWindow()->statusBar()->showMessage( + tr("Too few points picked in the left view." + " At least %1 points are needed.").arg(myPickPoints)); + } + else if (myFixedGroup.countPoints() < myPickPoints) { + Gui::getMainWindow()->statusBar()->showMessage( + tr("Too few points picked in the right view." + " At least %1 points are needed.").arg(myPickPoints)); + } + else if (myAlignModel.activeGroup().countPoints() != myFixedGroup.countPoints()) { + Gui::getMainWindow()->statusBar()->showMessage( + tr("Different number of points picked in left and right view. " + "On the left view %1 points are picked, " + "on the right view %2 points are picked.") + .arg(myAlignModel.activeGroup().countPoints()) + .arg(myFixedGroup.countPoints())); + } +} + +bool ManualAlignment::canAlign() const +{ + if (myAlignModel.activeGroup().countPoints() == myFixedGroup.countPoints()) { + if (myFixedGroup.countPoints() >= myPickPoints) + return true; + } + + return false; +} + +/** + * This method computes the alignment. For the calculation of the alignment the picked points of both views + * are taken. If the alignment fails false is returned, true otherwise. + */ +bool ManualAlignment::computeAlignment(const std::vector& movPts, + const std::vector& fixPts) +{ + assert((int)movPts.size() >= myPickPoints); + assert((int)fixPts.size() >= myPickPoints); + assert((int)movPts.size() == (int)fixPts.size()); + myTransform = Base::Placement(); + + if (movPts.size() == 1) { + // 1 point partial solution: Simple translation only + myTransform.setPosition(fixPts[0] - movPts[0]); + } + else if (movPts.size() == 2) { + const Base::Vector3d& p1 = movPts[0]; + const Base::Vector3d& p2 = movPts[1]; + Base::Vector3d d1 = p2-p1; + d1.Normalize(); + + const Base::Vector3d& q1 = fixPts[0]; + const Base::Vector3d& q2 = fixPts[1]; + Base::Vector3d d2 = q2-q1; + d2.Normalize(); + + myTransform = Private::transformation2x2(p1, d1, q1, d2); + } + else if (movPts.size() >= 3) { + const Base::Vector3d& p1 = movPts[0]; + const Base::Vector3d& p2 = movPts[1]; + const Base::Vector3d& p3 = movPts[2]; + Base::Vector3d d1 = p2-p1; + d1.Normalize(); + Base::Vector3d n1 = (p2-p1) % (p3-p1); + n1.Normalize(); + + const Base::Vector3d& q1 = fixPts[0]; + const Base::Vector3d& q2 = fixPts[1]; + const Base::Vector3d& q3 = fixPts[2]; + Base::Vector3d d2 = q2-q1; + d2.Normalize(); + Base::Vector3d n2 = (q2-q1) % (q3-q1); + n2.Normalize(); + + myTransform = Private::transformation3x3(p1, d1, n1, q1, d2, n2); + } + + return true; +} + +/** + * This method performs the actual alignment of view \a pView. + */ +void ManualAlignment::alignObject(App::DocumentObject *obj) +{ + if (obj->getTypeId().isDerivedFrom(App::GeoFeature::getClassTypeId())) { + App::GeoFeature* geom = static_cast(obj); + Base::Placement plm = geom->Placement.getValue(); + plm = this->myTransform * plm; + geom->Placement.setValue(plm); + } +} + +/** + * Creates a point element as visible feedback for the user. + */ +SoNode* ManualAlignment::pickedPointsSubGraph(const SbVec3f& p, const SbVec3f& n, int id) +{ + static const float color_table [10][3] = { + {1.0f,0.0f,0.0f}, // red + {0.0f,1.0f,0.0f}, // green + {0.0f,0.0f,1.0f}, // blue + {1.0f,1.0f,0.0f}, // yellow + {0.0f,1.0f,1.0f}, // cyan + {0.7f,0.0f,0.0f}, + {0.0f,0.7f,0.0f}, + {0.7f,0.7f,0.0f}, + {0.7f,0.0f,0.5f}, + {1.0f,0.7f,0.0f} + }; + + int index = (id-1) % 10; + + SoRegPoint* probe = new SoRegPoint(); + probe->base.setValue(p); + probe->normal.setValue(n); + probe->color.setValue(color_table[index][0],color_table[index][1],color_table[index][2]); + SbString s; + probe->text.setValue(s.sprintf("RegPoint_%d", id)); + return probe; +} + +/** + * Handle if the current document is about to being closed. + */ +void ManualAlignment::slotDeletedDocument(const Gui::Document& Doc) +{ + if (&Doc == this->myDocument) + reset(); +} + +/** + * Handle if the a view provider is about to being destroyed. + */ +void ManualAlignment::slotDeletedObject(const Gui::ViewProvider& Obj) +{ + // remove the view provider either from the left or the right view + if (Obj.getTypeId().isDerivedFrom(Gui::ViewProviderDocumentObject::getClassTypeId())) { + // remove the view provider immediately from the split window + bool found = false; + Gui::ViewProviderDocumentObject* vp = const_cast + (static_cast(&Obj)); + if (myAlignModel.activeGroup().hasView(vp)) { + myViewer->getViewer(0)->removeViewProvider(vp); + found = true; + } + if (myFixedGroup.hasView(vp)) { + myViewer->getViewer(1)->removeViewProvider(vp); + found = true; + } + + if (found) + cancel(); + } +} + +void ManualAlignment::onAlign() +{ + align(); +} + +void ManualAlignment::onRemoveLastPointMoveable() +{ + int nPoints = myAlignModel.activeGroup().countPoints(); + if (nPoints > 0) { + myAlignModel.activeGroup().removeLastPoint(); + d->picksepLeft->removeChild(nPoints-1); + } +} + +void ManualAlignment::onRemoveLastPointFixed() +{ + int nPoints = myFixedGroup.countPoints(); + if (nPoints > 0) { + myFixedGroup.removeLastPoint(); + d->picksepRight->removeChild(nPoints-1); + } +} + +void ManualAlignment::onClear() +{ + myAlignModel.activeGroup().clear(); + myFixedGroup.clear(); + + d->picksepLeft->removeAllChildren(); + d->picksepRight->removeAllChildren(); +} + +void ManualAlignment::onCancel() +{ + cancel(); +} + +void ManualAlignment::probePickedCallback(void * ud, SoEventCallback * n) +{ + Gui::View3DInventorViewer* view = reinterpret_cast(n->getUserData()); + const SoEvent* ev = n->getEvent(); + if (ev->getTypeId() == SoMouseButtonEvent::getClassTypeId()) { + // set as handled + n->getAction()->setHandled(); + n->setHandled(); + + const SoMouseButtonEvent * mbe = static_cast(ev); + if (mbe->getButton() == SoMouseButtonEvent::BUTTON1 && mbe->getState() == SoButtonEvent::DOWN) { + // if we are in 'align' mode then handle the click event + ManualAlignment* self = ManualAlignment::instance(); + // Get the closest point to the camera of the whole scene. + // This point doesn't need to be part of this view provider. + Gui::WaitCursor wc; + const SoPickedPoint * point = n->getPickedPoint(); + if (point) { + Gui::ViewProvider* vp = static_cast(view->getViewProviderByPath(point->getPath())); + if (vp && vp->getTypeId().isDerivedFrom(Gui::ViewProviderDocumentObject::getClassTypeId())) { + Gui::ViewProviderDocumentObject* that = static_cast(vp); + self->applyPickedProbe(that, point); + + const SbVec3f& vec = point->getPoint(); + Gui::getMainWindow()->statusBar()->showMessage( + tr("Point picked at (%1,%2,%3)") + .arg(vec[0]).arg(vec[1]).arg(vec[2])); + } + } + else { + Gui::getMainWindow()->statusBar()->showMessage( + tr("No point was picked")); + } + } + else if (mbe->getButton() == SoMouseButtonEvent::BUTTON2 && mbe->getState() == SoButtonEvent::UP) { + ManualAlignment* self = ManualAlignment::instance(); + if (self->myAlignModel.isEmpty() || self->myFixedGroup.isEmpty()) + return; + self->showInstructions(); + int nPoints; + if (view == self->myViewer->getViewer(0)) + nPoints = self->myAlignModel.activeGroup().countPoints(); + else + nPoints = self->myFixedGroup.countPoints(); + QMenu menu; + QAction* fi = menu.addAction(QLatin1String("&Align")); + QAction* rem = menu.addAction(QLatin1String("&Remove last point")); + //QAction* cl = menu.addAction("C&lear"); + QAction* ca = menu.addAction(QLatin1String("&Cancel")); + fi->setEnabled(self->canAlign()); + rem->setEnabled(nPoints > 0); + menu.addSeparator(); + QAction* sync = menu.addAction(QLatin1String("&Synchronize views")); + sync->setCheckable(true); + if (self->d->sensorCam1->getAttachedNode()) + sync->setChecked(true); + QAction* id = menu.exec(QCursor::pos()); + if (id == fi) { + // call align->align(); + QTimer::singleShot(300, self, SLOT(onAlign())); + } + else if ((id == rem) && (view == self->myViewer->getViewer(0))) { + QTimer::singleShot(300, self, SLOT(onRemoveLastPointMoveable())); + } + else if ((id == rem) && (view == self->myViewer->getViewer(1))) { + QTimer::singleShot(300, self, SLOT(onRemoveLastPointFixed())); + } + //else if (id == cl) { + // // call align->clear(); + // QTimer::singleShot(300, self, SLOT(onClear())); + //} + else if (id == ca) { + // call align->cancel(); + QTimer::singleShot(300, self, SLOT(onCancel())); + } + else if (id == sync) { + // setup sensor connection + if (sync->isChecked()) { + SoCamera* cam1 = self->myViewer->getViewer(0)->getCamera(); + SoCamera* cam2 = self->myViewer->getViewer(1)->getCamera(); + if (cam1 && cam2) { + self->d->sensorCam1->attach(cam1); + self->d->rot_cam1 = cam1->orientation.getValue(); + self->d->pos_cam1 = cam1->position.getValue(); + self->d->sensorCam2->attach(cam2); + self->d->rot_cam2 = cam2->orientation.getValue(); + self->d->pos_cam2 = cam2->position.getValue(); + } + } + else { + self->d->sensorCam1->detach(); + self->d->sensorCam2->detach(); + } + } + } + } +} + +/** + * This method stores the picked point \a pnt from the view provider \a prov. If enough points in both windows have been picked + * the alignment gets invoked. + */ +void ManualAlignment::applyPickedProbe(Gui::ViewProviderDocumentObject* prov, const SoPickedPoint* pnt) +{ + const SbVec3f& vec = pnt->getPoint(); + const SbVec3f& nor = pnt->getNormal(); + + // add to the list for the non-aligned view in the left view + if (myAlignModel.activeGroup().hasView(prov)) { + myAlignModel.activeGroup().addPoint(Base::Vector3d(vec[0],vec[1],vec[2])); + // Adds a point marker for the picked point. + d->picksepLeft->addChild(pickedPointsSubGraph(vec, nor, myAlignModel.activeGroup().countPoints())); + } + else if (myFixedGroup.hasView(prov)) { + myFixedGroup.addPoint(Base::Vector3d(vec[0],vec[1],vec[2])); + // Adds a point marker for the picked point. + d->picksepRight->addChild(pickedPointsSubGraph(vec, nor, myFixedGroup.countPoints())); + } +} + +#include "moc_ManualAlignment.cpp" + diff --git a/src/Gui/ManualAlignment.h b/src/Gui/ManualAlignment.h new file mode 100644 index 000000000..78a93391f --- /dev/null +++ b/src/Gui/ManualAlignment.h @@ -0,0 +1,257 @@ +/*************************************************************************** + * Copyright (c) 2012 Werner Mayer * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + + +#ifndef GUI_MANUALALIGNMENT_H +#define GUI_MANUALALIGNMENT_H + +#include +#include +#include +#include +#include +#include + +class SbVec3f; +class SoPickedPoint; +class SoEventCallback; + +namespace Gui { +class Document; +class AlignmentView; +class View3DInventorViewer; + +/** + * The AlignemntGroup class is the base for fixed and movable groups. + * @author Werner Mayer + */ +class GuiExport AlignmentGroup +{ +protected: + AlignmentGroup(); + ~AlignmentGroup(); + +public: + /** + * Add a mesh to the group. + */ + void addView(App::DocumentObject*); + std::vector getViews() const; + /** + * Checks for the view provider of one of the added views. + */ + bool hasView(Gui::ViewProviderDocumentObject*) const; + /** + * Remove a previously added view by its view provider. + */ + void removeView(Gui::ViewProviderDocumentObject*); + /** + * Add the group and therefore all its added view providers to the Inventor tree. + */ + void addToViewer(Gui::View3DInventorViewer*) const; + /** + * Remove all the view providers from the Inventor tree. + */ + void removeFromViewer(Gui::View3DInventorViewer*) const; + void setRandomColor(); + /** + * Returns the document of the added views. + */ + Gui::Document* getDocument() const; + /** + * Add a point to an array of picked points. + */ + void addPoint(const Base::Vector3d&); + /** + * Remove last point from array of picked points. + */ + void removeLastPoint(); + /** + * Count the number of picked points. + */ + int countPoints() const; + /** + * Return an array of picked points. + */ + const std::vector& getPoints() const; + /** + * Clear all picked points. + */ + void clearPoints(); + /** + * Set or unset the alignable mode for the added views. If a view is not alignable it also not pickable. + */ + void setAlignable(bool); + void moveTo(AlignmentGroup&); + /** + * Clear the list of added views. + */ + void clear(); + /** + * Checks whether the list of added views is empty or not. + */ + bool isEmpty() const; + /** + * Return the number of added views. + */ + int count() const; + +protected: + std::vector _pickedPoints; + std::vector _views; +}; + +/** + * The FixedGroup class can be used for a fixed group of views. + * @author Werner Mayer + */ +class GuiExport MovableGroup : public AlignmentGroup +{ +public: + MovableGroup(); + ~MovableGroup(); +}; + +/** + * The FixedGroup class can be used for a fixed group of views. + * @author Werner Mayer + */ +class GuiExport FixedGroup : public AlignmentGroup +{ +public: + FixedGroup(); + ~FixedGroup(); +}; + +/** + * The MovableGroupModel class keeps an array of movable groups. + * @author Werner Mayer + */ +class GuiExport MovableGroupModel +{ +public: + MovableGroupModel(); + ~MovableGroupModel(); + + void addGroup(const MovableGroup&); + void addGroups(const std::map&); + MovableGroup& activeGroup(); + const MovableGroup& activeGroup() const; + void continueAlignment(); + void clear(); + bool isEmpty() const; + int count() const; + +protected: + void removeActiveGroup(); + +private: + std::vector _groups; +}; + +/** + * @author Werner Mayer + */ +class GuiExport ManualAlignment : public QObject +{ + Q_OBJECT + +protected: + ManualAlignment(); + ~ManualAlignment(); + +public: + static ManualAlignment* instance(); + static void destruct(); + static bool hasInstance(); + + void setMinPoints(int minPoints); + void setFixedGroup(const FixedGroup&); + void setModel(const MovableGroupModel&); + void clearAll(); + + void setViewingDirections(const Base::Vector3d& view1, const Base::Vector3d& up1, + const Base::Vector3d& view2, const Base::Vector3d& up2); + void startAlignment(Base::Type mousemodel); + void finish(); + void align(); + bool canAlign() const; + void cancel(); + + const Base::Placement & getTransform() const + { return myTransform; } + void alignObject(App::DocumentObject*); + + // Observer stuff + /// Checks if the given object is about to be removed + void slotDeletedDocument(const Gui::Document& Doc); + /// Checks if the given document is about to be closed + void slotDeletedObject(const Gui::ViewProvider& Obj); + +protected: + bool computeAlignment(const std::vector& unnavPts, const std::vector& navigPts); + void continueAlignment(); + void showInstructions(); + /** @name Probe picking */ + //@{ + static void probePickedCallback(void * ud, SoEventCallback * n); + void applyPickedProbe(Gui::ViewProviderDocumentObject*, const SoPickedPoint* pnt); + //@} + +protected Q_SLOTS: + void reset(); + void onAlign(); + void onRemoveLastPointMoveable(); + void onRemoveLastPointFixed(); + void onClear(); + void onCancel(); + +Q_SIGNALS: + void emitCanceled(); + void emitFinished(); + +private: + SoNode* pickedPointsSubGraph(const SbVec3f& p, const SbVec3f& n, int id); + void closeViewer(); + + static ManualAlignment* _instance; + + typedef boost::BOOST_SIGNALS_NAMESPACE::connection Connection; + Connection connectApplicationDeletedDocument; + Connection connectDocumentDeletedObject; + + FixedGroup myFixedGroup; + MovableGroupModel myAlignModel; + QPointer myViewer; + Gui::Document* myDocument; + int myPickPoints; + Base::Placement myTransform; + + class Private; + Private* d; +}; + +} // namespace Gui + + +#endif // GUI_MANUALALIGNMENT_H + diff --git a/src/Gui/SoAxisCrossKit.cpp b/src/Gui/SoAxisCrossKit.cpp index 6eed7457d..d05f85670 100644 --- a/src/Gui/SoAxisCrossKit.cpp +++ b/src/Gui/SoAxisCrossKit.cpp @@ -24,20 +24,34 @@ #include "PreCompiled.h" #ifndef _PreComp_ +# ifdef FC_OS_WIN32 +# include +# endif +# ifdef FC_OS_MACOSX +# include +# else +# include +# endif # include # include +# include +# include +# include +# include +# include +# include # include # include # include # include # include # include +# include # include # include +# include +# include # include -# include -# include -# include #endif @@ -217,3 +231,129 @@ SoAxisCrossKit::createAxes() set("zAxis.pickStyle", "style UNPICKABLE"); set("zHead.pickStyle", "style UNPICKABLE"); } + +// -------------------------------------------------------------- + +SO_NODE_SOURCE(SoRegPoint); + +void SoRegPoint::initClass() +{ + SO_NODE_INIT_CLASS(SoRegPoint, SoShape, "Shape"); +} + +SoRegPoint::SoRegPoint() +{ + SO_NODE_CONSTRUCTOR(SoRegPoint); + + SO_NODE_ADD_FIELD(base, (SbVec3f(0,0,0))); + SO_NODE_ADD_FIELD(normal, (SbVec3f(1,1,1))); + SO_NODE_ADD_FIELD(length, (3.0)); + SO_NODE_ADD_FIELD(color, (1.0f, 0.447059f, 0.337255f)); + SO_NODE_ADD_FIELD(text, ("")); + + root = new SoSeparator(); + root->ref(); + + // translation + SoTranslation* move = new SoTranslation(); + move->translation.setValue(base.getValue() + normal.getValue() * length.getValue()); + root->addChild(move); + + // sub-group + SoBaseColor* col = new SoBaseColor(); + col->rgb.setValue(this->color.getValue()); + + SoFontStyle* font = new SoFontStyle; + font->size = 14; + + SoSeparator* sub = new SoSeparator(); + sub->addChild(col); + sub->addChild(font); + sub->addChild(new SoText2()); + root->addChild(sub); +} + +SoRegPoint::~SoRegPoint() +{ + root->unref(); +} + +/** + * Renders the probe with text label and a bullet at the base point. + */ +void SoRegPoint::GLRender(SoGLRenderAction *action) +{ + if (shouldGLRender(action)) + { + SoState* state = action->getState(); + state->push(); + SoMaterialBundle mb(action); + SoTextureCoordinateBundle tb(action, TRUE, FALSE); + SoLazyElement::setLightModel(state, SoLazyElement::BASE_COLOR); + mb.sendFirst(); // make sure we have the correct material + + SbVec3f p1 = base.getValue(); + SbVec3f p2 = p1 + normal.getValue() * length.getValue(); + + glLineWidth(1.0f); + glColor3fv(color.getValue().getValue()); + glBegin(GL_LINE_STRIP); + glVertex3d(p1[0], p1[1], p1[2]); + glVertex3d(p2[0], p2[1], p2[2]); + glEnd(); + glPointSize(5.0f); + glBegin(GL_POINTS); + glVertex3fv(p1.getValue()); + glEnd(); + glPointSize(2.0f); + glBegin(GL_POINTS); + glVertex3fv(p2.getValue()); + glEnd(); + + root->GLRender(action); + state->pop(); + } +} + +void SoRegPoint::generatePrimitives(SoAction* action) +{ +} + +/** + * Sets the bounding box of the probe to \a box and its center to \a center. + */ +void SoRegPoint::computeBBox(SoAction *action, SbBox3f &box, SbVec3f ¢er) +{ + root->doAction(action); + if (action->getTypeId().isDerivedFrom(SoGetBoundingBoxAction::getClassTypeId())) + static_cast(action)->resetCenter(); + + SbVec3f p1 = base.getValue(); + SbVec3f p2 = p1 + normal.getValue() * length.getValue(); + + box.extendBy(p1); + box.extendBy(p2); + + center = box.getCenter(); +} + +void SoRegPoint::notify(SoNotList * node) +{ + SoField * f = node->getLastField(); + if (f == &this->base || f == &this->normal || f == &this->length) { + SoTranslation* move = static_cast(root->getChild(0)); + move->translation.setValue(base.getValue() + normal.getValue() * length.getValue()); + } + else if (f == &this->color) { + SoSeparator* sub = static_cast(root->getChild(1)); + SoBaseColor* col = static_cast(sub->getChild(0)); + col->rgb = this->color.getValue(); + } + else if (f == &this->text) { + SoSeparator* sub = static_cast(root->getChild(1)); + SoText2* label = static_cast(sub->getChild(2)); + label->string = this->text.getValue(); + } + + SoShape::notify(node); +} diff --git a/src/Gui/SoAxisCrossKit.h b/src/Gui/SoAxisCrossKit.h index bb1a24934..488c51ee8 100644 --- a/src/Gui/SoAxisCrossKit.h +++ b/src/Gui/SoAxisCrossKit.h @@ -27,6 +27,8 @@ #include #include #include +#include +#include class SbViewport; class SoState; @@ -84,6 +86,33 @@ private: virtual ~SoAxisCrossKit(); }; +class GuiExport SoRegPoint : public SoShape { + typedef SoShape inherited; + + SO_NODE_HEADER(SoRegPoint); + +public: + static void initClass(); + SoRegPoint(); + + void notify(SoNotList * node); + + SoSFVec3f base; + SoSFVec3f normal; + SoSFFloat length; + SoSFColor color; + SoSFString text; + +protected: + virtual ~SoRegPoint(); + virtual void GLRender(SoGLRenderAction *action); + virtual void computeBBox(SoAction *action, SbBox3f &box, SbVec3f ¢er); + virtual void generatePrimitives(SoAction *action); + +private: + SoSeparator* root; +}; + } // namespace Gui #endif // GUI_SOSHAPESCALE_H diff --git a/src/Gui/SoFCDB.cpp b/src/Gui/SoFCDB.cpp index 46435be06..ddf074ca1 100644 --- a/src/Gui/SoFCDB.cpp +++ b/src/Gui/SoFCDB.cpp @@ -95,6 +95,7 @@ void Gui::SoFCDB::init() TranslateManip ::initClass(); SoShapeScale ::initClass(); SoAxisCrossKit ::initClass(); + SoRegPoint ::initClass(); SoDrawingGrid ::initClass(); PropertyItem ::init(); diff --git a/src/Gui/SplitView3DInventor.cpp b/src/Gui/SplitView3DInventor.cpp index f80532af8..7014aaa77 100644 --- a/src/Gui/SplitView3DInventor.cpp +++ b/src/Gui/SplitView3DInventor.cpp @@ -41,42 +41,29 @@ using namespace Gui; -TYPESYSTEM_SOURCE_ABSTRACT(Gui::SplitView3DInventor,Gui::MDIView); +TYPESYSTEM_SOURCE_ABSTRACT(Gui::AbstractSplitView,Gui::MDIView); -SplitView3DInventor::SplitView3DInventor(int views, Gui::Document* pcDocument, QWidget* parent, Qt::WFlags wflags) +AbstractSplitView::AbstractSplitView(Gui::Document* pcDocument, QWidget* parent, Qt::WFlags wflags) : MDIView(pcDocument,parent, wflags) { // important for highlighting setMouseTracking(true); - +} + +AbstractSplitView::~AbstractSplitView() +{ + hGrp->Detach(this); + for (std::vector::iterator it = _viewer.begin(); it != _viewer.end(); ++it) { + delete *it; + } +} + +void AbstractSplitView::setupSettings() +{ // attach Parameter Observer hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/View"); hGrp->Attach(this); - QSplitter* mainSplitter=0; - - if (views <= 3) { - mainSplitter = new QSplitter(Qt::Horizontal, this); - _viewer.push_back(new View3DInventorViewer(mainSplitter)); - _viewer.push_back(new View3DInventorViewer(mainSplitter)); - if (views==3) - _viewer.push_back(new View3DInventorViewer(mainSplitter)); - } - else { - mainSplitter = new QSplitter(Qt::Vertical, this); - QSplitter *topSplitter = new QSplitter(Qt::Horizontal, mainSplitter); - QSplitter *botSplitter = new QSplitter(Qt::Horizontal, mainSplitter); - _viewer.push_back(new View3DInventorViewer(topSplitter)); - _viewer.push_back(new View3DInventorViewer(topSplitter)); - for (int i=2;isetOpaqueResize( true ); - botSplitter->setOpaqueResize( true ); - } - - mainSplitter->show(); - setCentralWidget(mainSplitter); - // apply the user settings OnChange(*hGrp,"EyeDistance"); OnChange(*hGrp,"CornerCoordSystem"); @@ -100,21 +87,13 @@ SplitView3DInventor::SplitView3DInventor(int views, Gui::Document* pcDocument, Q OnChange(*hGrp,"NavigationStyle"); } -SplitView3DInventor::~SplitView3DInventor() -{ - hGrp->Detach(this); - for (std::vector::iterator it = _viewer.begin(); it != _viewer.end(); ++it) { - delete *it; - } -} - -View3DInventorViewer* SplitView3DInventor::getViewer(unsigned int n) const +View3DInventorViewer* AbstractSplitView::getViewer(unsigned int n) const { return (_viewer.size() > n ? _viewer[n] : 0); } /// Observer message from the ParameterGrp -void SplitView3DInventor::OnChange(ParameterGrp::SubjectType &rCaller,ParameterGrp::MessageType Reason) +void AbstractSplitView::OnChange(ParameterGrp::SubjectType &rCaller,ParameterGrp::MessageType Reason) { const ParameterGrp& rGrp = static_cast(rCaller); if (strcmp(Reason,"HeadlightColor") == 0) { @@ -266,17 +245,17 @@ void SplitView3DInventor::OnChange(ParameterGrp::SubjectType &rCaller,ParameterG } } -void SplitView3DInventor::onUpdate(void) +void AbstractSplitView::onUpdate(void) { update(); } -const char *SplitView3DInventor::getName(void) const +const char *AbstractSplitView::getName(void) const { return "SplitView3DInventor"; } -bool SplitView3DInventor::onMsg(const char* pMsg, const char** ppReturn) +bool AbstractSplitView::onMsg(const char* pMsg, const char** ppReturn) { if (strcmp("ViewFit",pMsg) == 0 ) { for (std::vector::iterator it = _viewer.begin(); it != _viewer.end(); ++it) @@ -346,7 +325,7 @@ bool SplitView3DInventor::onMsg(const char* pMsg, const char** ppReturn) return false; } -bool SplitView3DInventor::onHasMsg(const char* pMsg) const +bool AbstractSplitView::onHasMsg(const char* pMsg) const { if (strcmp("ViewFit",pMsg) == 0) { return true; @@ -375,7 +354,46 @@ bool SplitView3DInventor::onHasMsg(const char* pMsg) const return false; } -void SplitView3DInventor::setCursor(const QCursor& aCursor) +void AbstractSplitView::setCursor(const QCursor& aCursor) { //_viewer->getWidget()->setCursor(aCursor); } + +// ------------------------------------------------------ + +TYPESYSTEM_SOURCE_ABSTRACT(Gui::SplitView3DInventor, Gui::AbstractSplitView); + +SplitView3DInventor::SplitView3DInventor(int views, Gui::Document* pcDocument, QWidget* parent, Qt::WFlags wflags) + : AbstractSplitView(pcDocument,parent, wflags) +{ + QSplitter* mainSplitter=0; + + if (views <= 3) { + mainSplitter = new QSplitter(Qt::Horizontal, this); + _viewer.push_back(new View3DInventorViewer(mainSplitter)); + _viewer.push_back(new View3DInventorViewer(mainSplitter)); + if (views==3) + _viewer.push_back(new View3DInventorViewer(mainSplitter)); + } + else { + mainSplitter = new QSplitter(Qt::Vertical, this); + QSplitter *topSplitter = new QSplitter(Qt::Horizontal, mainSplitter); + QSplitter *botSplitter = new QSplitter(Qt::Horizontal, mainSplitter); + _viewer.push_back(new View3DInventorViewer(topSplitter)); + _viewer.push_back(new View3DInventorViewer(topSplitter)); + for (int i=2;isetOpaqueResize( true ); + botSplitter->setOpaqueResize( true ); + } + + mainSplitter->show(); + setCentralWidget(mainSplitter); + + // apply the user settings + setupSettings(); +} + +SplitView3DInventor::~SplitView3DInventor() +{ +} diff --git a/src/Gui/SplitView3DInventor.h b/src/Gui/SplitView3DInventor.h index c4596e9a9..de7254ec4 100644 --- a/src/Gui/SplitView3DInventor.h +++ b/src/Gui/SplitView3DInventor.h @@ -36,13 +36,13 @@ class View3DInventorViewer; /** The SplitView3DInventor class allows to create a window with two or more Inventor views. * \author Werner Mayer */ -class GuiExport SplitView3DInventor : public MDIView,public ParameterGrp::ObserverType +class GuiExport AbstractSplitView : public MDIView, public ParameterGrp::ObserverType { TYPESYSTEM_HEADER(); public: - SplitView3DInventor(int views, Gui::Document* pcDocument, QWidget* parent, Qt::WFlags wflags=0); - ~SplitView3DInventor(); + AbstractSplitView(Gui::Document* pcDocument, QWidget* parent, Qt::WFlags wflags=0); + ~AbstractSplitView(); virtual const char *getName(void) const; @@ -56,14 +56,27 @@ public: void setCursor(const QCursor&); +protected: + void setupSettings(); + protected: /// handle to the viewer parameter group ParameterGrp::handle hGrp; - -private: std::vector _viewer; }; +/** The SplitView3DInventor class allows to create a window with two or more Inventor views. + * \author Werner Mayer + */ +class GuiExport SplitView3DInventor : public AbstractSplitView +{ + TYPESYSTEM_HEADER(); + +public: + SplitView3DInventor(int views, Gui::Document* pcDocument, QWidget* parent, Qt::WFlags wflags=0); + ~SplitView3DInventor(); +}; + } // namespace Gui #endif //GUI_SPLITVIEW3DINVENTOR_H diff --git a/src/Gui/Workbench.cpp b/src/Gui/Workbench.cpp index d6b82d4ab..dc32d7dc7 100644 --- a/src/Gui/Workbench.cpp +++ b/src/Gui/Workbench.cpp @@ -441,7 +441,8 @@ MenuItem* StdWorkbench::setupMenuBar() const edit->setCommand("&Edit"); *edit << "Std_Undo" << "Std_Redo" << "Separator" << "Std_Cut" << "Std_Copy" << "Std_Paste" << "Std_DuplicateSelection" << "Separator" - << "Std_Refresh" << "Std_SelectAll" << "Std_Delete" << "Std_Placement" + << "Std_Refresh" << "Std_SelectAll" << "Std_Delete" + << "Std_Placement" << "Std_Alignment" << "Std_Edit" << "Separator" << "Std_DlgPreferences"; // Standard views diff --git a/src/Mod/Complete/Gui/Workbench.cpp b/src/Mod/Complete/Gui/Workbench.cpp index 45a2faa03..80a0336dd 100644 --- a/src/Mod/Complete/Gui/Workbench.cpp +++ b/src/Mod/Complete/Gui/Workbench.cpp @@ -132,7 +132,8 @@ Gui::MenuItem* Workbench::setupMenuBar() const edit->setCommand("&Edit"); *edit << "Std_Undo" << "Std_Redo" << "Separator" << "Std_Cut" << "Std_Copy" << "Std_Paste" << "Std_DuplicateSelection" << "Separator" - << "Std_Refresh" << "Std_SelectAll" << "Std_Delete" << "Std_Placement" + << "Std_Refresh" << "Std_SelectAll" << "Std_Delete" + << "Std_Placement" << "Std_Alignment" << "Separator" << "Std_DlgPreferences"; // Standard views