diff --git a/compositemodel/include/GoTools/compositemodel/HedgeSurface.h b/compositemodel/include/GoTools/compositemodel/HedgeSurface.h new file mode 100644 index 00000000..70d43682 --- /dev/null +++ b/compositemodel/include/GoTools/compositemodel/HedgeSurface.h @@ -0,0 +1,250 @@ +/* + * Copyright (C) 1998, 2000-2007, 2010, 2011, 2012, 2013 SINTEF ICT, + * Applied Mathematics, Norway. + * + * Contact information: E-mail: tor.dokken@sintef.no + * SINTEF ICT, Department of Applied Mathematics, + * P.O. Box 124 Blindern, + * 0314 Oslo, Norway. + * + * This file is part of GoTools. + * + * GoTools is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * GoTools 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with GoTools. If not, see + * <http://www.gnu.org/licenses/>. + * + * In accordance with Section 7(b) of the GNU Affero General Public + * License, a covered work must retain the producer line in every data + * file that is created or manipulated using GoTools. + * + * Other Usage + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial activities involving the GoTools library without + * disclosing the source code of your own applications. + * + * This file may be used in accordance with the terms contained in a + * written agreement between you and SINTEF ICT. + */ + +#ifndef _HEDGESURFACE_H +#define _HEDGESURFACE_H + +#include "GoTools/compositemodel/ftSurface.h" +#include "GoTools/geometry/ClassType.h" +//#include "GoTools/compositemodel/RevEngRegion.h" + +namespace Go { + +class RevEngRegion; + class CurveOnSurface; + + /// Additional information to the ClassType of a ParamSurface to distinguish + /// between different rotational surfaces. LINEARSWEPT_SURF is currently not + /// active while ROTATIONALSWEPT_SURF is not implemented + enum + { + SURF_TYPE_UNDEF, LINEARSWEPT_SURF, ROTATIONALSWEPT_SURF + }; + + /** HedgeSurface - A topological surface associated with a RevEngRegion. + The class provides extra information and functionality compared to ftSurface, + mainly related to information about the RevEngRegion. + * + */ + +class HedgeSurface : public ftSurface +{ +public: + + /// Constructor + HedgeSurface(); + + /// Constructor given geometry surface and associated region + HedgeSurface(shared_ptr<ParamSurface> sf, RevEngRegion *region); + + /// Constructor given geometry surface and a number of associated regions. Not active + HedgeSurface(shared_ptr<ParamSurface> sf, std::vector<RevEngRegion*>& region); + + /// Destructor + ~HedgeSurface(); + + /// Add information required to define a linear swept spline surface + void setLinearSweepInfo(shared_ptr<SplineCurve> profile, + Point startpt, Point endpt) + { + surf_code_ = LINEARSWEPT_SURF; + profile_ = profile; + sweep1_ = startpt; + sweep2_ = endpt; + } + + /// Add information required to define a rotational swept spline surface. Not implemented + void setRotationalSweepInfo(shared_ptr<SplineCurve> profile, + Point location, Point axis) + { + surf_code_ = ROTATIONALSWEPT_SURF; + profile = profile_; + sweep1_ = location; + sweep2_ = axis; + } + + /// Dimension of geometry space (should be 3) + int dimension() + { + return surface()->dimension(); + } + + /// Number of points in associated region(s) + int numPoints(); + + /// Class type of geometry surface and possible swept surface code + ClassType instanceType(int& code); + + /// Enquire if the surfae is a plane + bool isPlane() + { + int code; + return (instanceType(code) == Class_Plane); + } + + /// Enquire if the surfae is a cylinder + bool isCylinder() + { + int code; + return (instanceType(code) == Class_Cylinder); + } + + /// Enquire if the surfae is a sphere + bool isSphere() + { + int code; + return (instanceType(code) == Class_Sphere); + } + + /// Enquire if the surfae is a torus + bool isTorus() + { + int code; + return (instanceType(code) == Class_Torus); + } + + /// Enquire if the surfae is a cone + bool isCone() + { + int code; + return (instanceType(code) == Class_Cone); + } + + /// Enquire if the surfae is a freeform surface + bool isSpline() + { + int code; + return (instanceType(code) == Class_SplineSurface); + } + + /// Fetch associated region(s) + std::vector<RevEngRegion*> getRegions() + { + return regions_; + } + + /// Number of associated regions. Expected to be one + int numRegions() + { + return (int)regions_.size(); + } + + /// Fetch specified region + RevEngRegion* getRegion(int ix) + { + if (ix < 0 || ix >= (int)regions_.size()) + return 0; + else + return regions_[ix]; + } + + /// Add region to collection of associated regions + void addRegion(RevEngRegion* reg); + + /// Remove region from collection of associated regions + bool removeRegion(RevEngRegion* reg); + + /// Bounding box containing associated regions points + BoundingBox regionsBox() + { + return bbox_; + } + + /// Check if the geometry surfaces if entity and other is of the same type and has + /// roughly the same characteristica. Is it a potential to merge surfaces? + bool isCompatible(HedgeSurface* other, double angtol, double approx_tol, + ClassType& type, double& score); + + /// Ensure that the associated geometry surface is bounded (e.g. not an unlimited plane) + void ensureSurfaceBounded(); + + /// Bound unbounded primary surfaces + void limitSurf(double diag = -1.0); + + /// Make bounded surface when trimming edges are missing. Bound the associated region points + /// in the parameter domain of the surface and transfer this information to this surface + bool trimWithPoints(double aeps); + + /// Store current stage of hedge surface to file + void store(std::ostream& os) const; + + /// Read hedge surface stage from file + void read(std::istream& is); + +private: + /// Region(s) to which this surface is associated (only one) + std::vector<RevEngRegion*> regions_; + + /// Bounding box of the associated region + BoundingBox bbox_; + + /// Additional class type information to specify swept spline surfaces + int surf_code_; + + /// The profile curve in a swept surface + shared_ptr<SplineCurve> profile_; + + /// Sweep direction + Point sweep1_; + Point sweep2_; + + bool updateSurfaceWithAxis(Point axis[3], int ix, double tol, double angtol); + + bool updatePlaneWithAxis(Point axis[3], int ix, double tol, double angtol); + + bool updateCylinderWithAxis(Point axis[3], int ix, double tol, double angtol); + + bool checkAccuracyAndUpdate(shared_ptr<ParamSurface> surf, double tol, + double angtol); + + bool hasBaseSf(); + + // Enquire if it is safe to intersect this surface and surf. Tangential intersections are + // unstable and can produce infinite loops + bool isTangential(HedgeSurface* surf); + + void doTrim(std::vector<shared_ptr<CurveOnSurface> >& int_cvs, + shared_ptr<BoundedSurface>& bdsf, + double tol, + std::vector<shared_ptr<HedgeSurface> >& added_sfs); + +}; +} + +#endif // _HEDGESURFACE_H diff --git a/compositemodel/include/GoTools/compositemodel/ImplicitApprox.h b/compositemodel/include/GoTools/compositemodel/ImplicitApprox.h new file mode 100644 index 00000000..3bca493f --- /dev/null +++ b/compositemodel/include/GoTools/compositemodel/ImplicitApprox.h @@ -0,0 +1,124 @@ +/* + * Copyright (C) 1998, 2000-2007, 2010, 2011, 2012, 2013 SINTEF ICT, + * Applied Mathematics, Norway. + * + * Contact information: E-mail: tor.dokken@sintef.no + * SINTEF ICT, Department of Applied Mathematics, + * P.O. Box 124 Blindern, + * 0314 Oslo, Norway. + * + * This file is part of GoTools. + * + * GoTools is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * GoTools 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with GoTools. If not, see + * <http://www.gnu.org/licenses/>. + * + * In accordance with Section 7(b) of the GNU Affero General Public + * License, a covered work must retain the producer line in every data + * file that is created or manipulated using GoTools. + * + * Other Usage + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial activities involving the GoTools library without + * disclosing the source code of your own applications. + * + * This file may be used in accordance with the terms contained in a + * written agreement between you and SINTEF ICT. + */ + +#ifndef _IMPLICITAPPROX_H_ +#define _IMPLICITAPPROX_H_ + +#include "GoTools/implicitization/BernsteinTetrahedralPoly.h" +#include "GoTools/utils/BaryCoordSystem.h" +#include "GoTools/utils/Point.h" + +namespace Go +{ + class RevEngPoint; + + /** + ImlicitApprox - Interface class to Go::implicitization for reverse engineering + purposes. Used only to approximate a point cloud with a plane (degree one). Higher + degree approximations are unstable for noisy point clouds + * + */ + class ImplicitApprox + { + public: + /// Constructor + ImplicitApprox(); + + /// Destructor + ~ImplicitApprox(); + + /// Approximate a group of RevEngPoints with a surface of degree degree. + /// Recommended only for degree one + void approx(std::vector<RevEngPoint*> points, int degree); + + /// Approximate several groups of RevEngPoints with a surface of degree degree. + /// Recommended only for degree one + void approx(std::vector<std::pair<std::vector<RevEngPoint*>::iterator, + std::vector<RevEngPoint*>::iterator> >& points, + int degree); + + /// Approximate a group of points with a surface of degree degree. + /// Recommended only for degree one + void approxPoints(std::vector<Point> points, int degree); + + /// Project initial point and direction onto implicit surface to get a point + /// in the surface and corresponding surface normal + bool projectPoint(Point point, Point dir, + Point& projpos, Point& normal); + + /// \param pt Input point + /// \param val Implicit distance between the point pt and the surface + /// \param grad Gradient at point pt + void evaluate(Point& pt, double& val, Point& grad); + + + private: + /// Degree of implicit surface + int degree_; + + /// Bernstein polynomials on a tetrahedron + BernsteinTetrahedralPoly implicit_; + + /// implicit_ differentiated + BernsteinTetrahedralPoly deriv1_, deriv2_, deriv3_, deriv4_; + + // Encapsulates a barycentric coordinate system. + BaryCoordSystem3D bc_; + double sigma_min_; + double eps_; + + double estimateDist(RevEngPoint* pt); + + void visualize(std::vector<RevEngPoint*> points, std::ostream& os); + + void visualize(std::vector<Point> points, Point& dir, std::ostream& os); + + void polynomialSurf(std::vector<Point>& pos_and_der, int degree, + std::vector<double>& coefs); + + void polynomialSurfAccuracy(std::vector<Point>& pos_and_der, + int degree, std::vector<double>& coefs, + double& maxfield, double& avfield, + double& maxdist, double& avdist, + int& ndiv, double& maxang, + double& avang); + }; +} + +#endif // _IMPLICITAPPROX_H_ diff --git a/compositemodel/include/GoTools/compositemodel/RevEng.h b/compositemodel/include/GoTools/compositemodel/RevEng.h new file mode 100644 index 00000000..9c471044 --- /dev/null +++ b/compositemodel/include/GoTools/compositemodel/RevEng.h @@ -0,0 +1,691 @@ +/* + * Copyright (C) 1998, 2000-2007, 2010, 2011, 2012, 2013 SINTEF ICT, + * Applied Mathematics, Norway. + * + * Contact information: E-mail: tor.dokken@sintef.no + * SINTEF ICT, Department of Applied Mathematics, + * P.O. Box 124 Blindern, + * 0314 Oslo, Norway. + * + * This file is part of GoTools. + * + * GoTools is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * GoTools 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with GoTools. If not, see + * <http://www.gnu.org/licenses/>. + * + * In accordance with Section 7(b) of the GNU Affero General Public + * License, a covered work must retain the producer line in every data + * file that is created or manipulated using GoTools. + * + * Other Usage + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial activities involving the GoTools library without + * disclosing the source code of your own applications. + * + * This file may be used in accordance with the terms contained in a + * written agreement between you and SINTEF ICT. + */ + +#ifndef _REVENG_H +#define _REVENG_H + +#include "GoTools/compositemodel/ftPointSet.h" +#include "GoTools/compositemodel/SurfaceModel.h" +#include "GoTools/compositemodel/RevEngRegion.h" +#include "GoTools/utils/Point.h" +#include "GoTools/utils/BoundingBox.h" +#include <string.h> + +namespace Go +{ + class RevEngPoint; + class HedgeSurface; + class RevEngEdge; + + /// Elementary surface types to be recognized + enum + { + PLANE, CYLINDER, SPHERE, CONE, TORUS + }; + + /// Characterization of model surface. Note that the default choice is ROUGH, + /// and that other choices are currently not supported + enum + { + SMOOTH=0, MEDIUM_ROUGH, ROUGH + }; + + /// Collection of surface information used in computation of global parameters + struct SurfaceProperties + { + int sfix_; + ClassType type_; + ClassType prev_type_; + Point dir_, loc_; + double rad1_, rad2_; + int num_points_; + int surfflag_; + + SurfaceProperties(int ix, ClassType type, int num, int surfflag, Point& dir, + Point& loc, ClassType prev_type=Class_Unknown, double rad1=-1, + double rad2=-1) + { + sfix_ = ix; + type_ = type; + num_points_ = num; + surfflag_ = surfflag; + dir_ = dir; + loc_ = loc; + prev_type_ = prev_type; + rad1_ = rad1; + rad2_ = rad2; + } + }; + + /// Information computed in adaptToMainAxis. Specifies model axes including + /// axis location and number of points supporting the information + struct AxisInfo + { + Point axis_; + std::vector<std::pair<Point,int> > plane_loc_; + std::vector<std::pair<Point,int> > rotational_loc_; + + AxisInfo(Point& axis) + { + axis_ = axis; + } + + void addPlaneLocation(Point& loc, int num) + { + plane_loc_.push_back(std::make_pair(loc,num)); + } + + void addRotationalLocation(Point& loc, int num) + { + rotational_loc_.push_back(std::make_pair(loc,num)); + } + }; + + /** RevEng - Reverse engineering engine. Workflow funcationality and + storage of data. + * + */ + + class RevEng + { + public: + /// Default constructor + RevEng(); + + /// Constructor + /// \param tri_sf Initial triangulated surface + RevEng(shared_ptr<ftPointSet> tri_sf); + + /// Destructor + ~RevEng(); + + /// Enhance points (triangle vertices) with estimated surface normal and + /// curvature information + void enhancePoints(); + + /// Classify points with respect to estimated curvature information + /// Possible classifications: edge point (high curvature), peak (negative mean + /// curvature and positive Gauss), ridge (negative mean, zero Gauss), + /// sridge (negative mean and Gauss), non (zero mean, positive Gauss, not expected), + /// flat (zero mean and Gauss), minsurf (zero mean, negative Gauss), + /// pit (positive mean and Gauss), valley (positive mean, zero Gauss) + /// and svalley (positive mean, negative Gauss) + void classifyPoints(); + + /// Group connected points with the same classification into regions + void segmentIntoRegions(); + + /// Create first surfaces from large regions, simultanously dismissing + /// points that do not belong to the region. Possible surfaces: planes, + /// cylinders and cones + void initialSurfaces(); + + /// Add adjacent regions to regions with surfaces if appropriate + void growSurfaces(); + + /// Identify coordinate axes corresponding to the current model and + /// update surfaces as appropriate (if their surface normal/axis almost + /// corresponds to a coordinate axis and the approximation error stays + /// limited) + void updateAxesAndSurfaces(); + + /// Compute intersection edges between defined neighbouring and almost + /// neighbouring surfaces provided that these surfaces + void firstEdges(); + + /// Second attempt to create surfaces. Some more regions might have grown to a + /// size that allows surface creation. Context information from adjacent surfaces + /// are used to guide the surface recognition. In addition to planes, cylinders and + /// cones are spheres and torii created. Context information is used to split + /// large composite regions. Additional edges may be created. + void surfaceCreation(int pass=1); + + /// Identify common surface axes/normals and define a local coordinate system. + /// Update surfaces accordingly + void updateRegionsAndSurfaces(int& ix, std::vector<RevEngRegion*>& grown_regions, + std::vector<HedgeSurface*>& adj_surfs); + + /// Second round in identifying main axes in the model. In addition to axis + /// direction is location registered. Surfaces are updated accordingly. + void adaptToMainAxis(); + + /// Third attempt to create surfaces. Small regions with similar characteristica + /// are merged and subject to surface recognition. The required region size is + /// reduced. Possible surfaces: planes, cylinders and cones. Additional edges + /// may be created. + void smallRegionSurfaces(); + + /// Create edge blends of type cylinder and torus associated with identified + /// edges. Blend surfaces with almost similar radius are made consistent. + void manageBlends1(); + + /// Bound blend surface along the edge. Identify corner blends of type + /// torus and 4-sided free form surface. Identify and extract trimming edges + /// from blend surface and define associated trimming edges for adjacent surfaces + void manageBlends2(); + + /// Compute missing trimming edges, between surfaces and towards regions without + /// surfaces. Extract relevant part of trimming edges, add missing edges as appropriate + /// and combine edges into trimming loops. Define bounded surfaces and associated faces. + void trimSurfaces(); + + /// Perform topology analysis and create surface model that can be exported in a g22 file + shared_ptr<SurfaceModel> createModel(); + + /// Compute approximation tolerance based on model properties + void setApproxTolerance(); + + /// Set approximation tolerance from application + void setApproxTol(double eps) + { + approx_tol_= eps; + } + + /// Enquire defined approximation tolerance + double getApproxTol() + { + return approx_tol_; + } + + /// Enquire edge classification type. Current: always curvature + int getEdgeClassificationType() + { + return edge_class_type_; + } + + /// Enquire parameter for edge classification. Relates to estimated curvature + /// radius in point and average length of triangle edges + double getCfac() + { + return cfac_; + } + + /// Set parameter for edge classification + void setCfac(double cfac) + { + cfac_ = cfac; + } + + /// Enquire point classification type. Current: always curvature + int getClassificationType() + { + return classification_type_; + } + + /// Enquire limit for when mean curvature is considered to be zero + double getMeanCurvatureZero() + { + return zero_H_; + } + + /// Set limit for when mean curvature is considered to be zero + void setMeanCurvatureZero(double zero_H) + { + zero_H_ = zero_H; + } + + + /// Enquire limit for when Gauss curvature is considered to be zero + double getGaussCurvatureZero() + { + return zero_K_; + } + + /// Set limit for when Gauss curvature is considered to be zero + void setGaussCurvatureZero(double zero_K) + { + zero_K_ = zero_K; + } + + /// Enquire preference for primary surfaces relative to free form surfaces. Always + /// primary, free form is currently disabled exept for some corner blends + int getElementaryPreferLevel() + { + return prefer_elementary_; + } + + /// Enquire model characterization involved in the definition of the approximation tolerance. + /// Currently: always ROUGH + int getModelCharacterization() + { + return model_character_; + } + + /// The main axes of the model is computed by updateAxesAndSurfaces(). Prelimenary axes + /// my be set prior to this function, but they should not be altered afterwards + void setMainAxis(Point mainaxis[3]) + { + mainaxis_[0] = mainaxis[0]; + mainaxis_[1] = mainaxis[1]; + mainaxis_[2] = mainaxis[2]; + } + + /// Enquire local coordinate axes + void getMainAxis(Point mainaxis[3]) + { + mainaxis[0] = mainaxis_[0]; + mainaxis[1] = mainaxis_[1]; + mainaxis[2] = mainaxis_[2]; + } + + /// Enquire current number of regions + int numRegions() + { + return (int)regions_.size(); + } + + /// Access specified region + shared_ptr<RevEngRegion> getRegion(int ix) + { + return regions_[ix]; + } + + /// Enquire number of identified surfaces + int numSurfaces() + { + return (int)surfaces_.size(); + } + + /// Access specified surface + shared_ptr<HedgeSurface> getSurface(int ix) + { + return surfaces_[ix]; + } + + /// Enquire minimum number of points in a region for being considered for surface + /// recognition + double getMinPointRegion() + { + return min_point_region_; + } + + /// Store current stage for later to restart the computation from this stage (not + /// accessible from manageBlends2 and later) + void storeGrownRegions(std::ostream& os); + + /// Read stored stage + void readGrownRegions(std::istream& is); + + /// Debug functionality + /// Write point groups and associated surfaces to files depending on the + /// the number of points in the groups (uses min_point_region_ to distinguish with + /// respect to size) + void writeRegionStage(std::ostream& of, std::ostream& ofm, std::ostream& ofs) const; + + /// Write point regions with an assoicated surface and the surface to file + void writeRegionWithSurf(std::ostream& of) const; + + /// Write edges and point regions appropriated to an associated blend surface to file + void writeEdgeStage(std::ostream& of) const; + + private: + /// Characterizes the surface of the current model. Currently always set to ROUGH + int model_character_; + + /// Triangulated surface + shared_ptr<ftPointSet> tri_sf_; + + /// Average length of triangle edges + double mean_edge_len_; + + /// Group points assumed to be associated one surface + std::vector<shared_ptr<RevEngRegion> > regions_; + + /// Points with different properties than their neighbouring points. + /// Regions with one point can also occur + std::vector<RevEngPoint*> single_points_; + + /// Recognized surfaces + std::vector<shared_ptr<HedgeSurface> > surfaces_; + + /// Recognized edges. Intersection curves between surfaces with additional information + std::vector<shared_ptr<RevEngEdge> > edges_; + + /// Final surface model including topology + shared_ptr<SurfaceModel> sfmodel_; + + /// Bounds the point cloud (triangulated surface) + BoundingBox bbox_; + + /// Minimum number of neighbouring connected points for estimating point properties + /// (surface normal and curvature) + int min_next_; + + // Stop searching for neighbouring points to estimate point properties when this number + // is reached + int max_next_; + + /// Factor for radius in which to search for neighbouring points + double rfac_; + + int edge_class_type_ = CURVATURE_EDGE; + int classification_type_ = CLASSIFICATION_CURVATURE; + + /// A vertex is considered an edge points if the estimated curvature radius is + /// less than cfac_ times the average length of triangulation edges in the vertex + double cfac_; + + /// Limit for when the cone angle corresponding to triangle normals indicate an edge + /// Not active + double norm_ang_lim_; + + /// Limit for when the cone angle correspondingto triangle normals indicate a plane + /// Not active + double norm_plane_lim_; + + /// When mean curvature is considered zero + double zero_H_; + + /// When Gauss curvature is considered zero + double zero_K_; + + /// Minimum number of points in a region to be considered for surface recognition + int min_point_region_; + + /// Approximation tolerance + double approx_tol_; + + /// Intersection tolerance + double int_tol_; + + /// Angular tolerance used in topology build. 5.0*anglim_ is used to check whether + /// the estimated normal in a point corresponds to the normal of a recognized surface + /// in the point + double anglim_; + + /// Used to decide if a point is an outlier + int max_nmb_outlier_; + + /// Preferance in selecting the surface associated to a point cloud, primary surface or + /// best fit surface. Default is 0. 0 = always, 1 = preferred, 2 = best accuracy + int prefer_elementary_; + + /// Coordinated axes associated to the model + Point mainaxis_[3]; + + /// Identified model axes including position + std::vector<AxisInfo> model_axis_; + + /// Collection of information related to smallRegionSurfaces() + struct SmallSurface + { + int axis_ix_, pos_ix_, lev_ix_; + vector<vector<RevEngPoint*> > assos_points_; + vector<shared_ptr<ElementarySurface> > surfs_; + vector<BoundingBox> bbox_; + int type_; // 1 = plane1, 2=plane2, 3=rotational, 4=from remaining + + SmallSurface(int ix1, int ix2, int ix3, int type, + vector<shared_ptr<ElementarySurface> >& surfs) + { + axis_ix_ = ix1; + pos_ix_ = ix2; + lev_ix_ = ix3; + type_ = type; + surfs_ = surfs; + } + + void addPoints(vector<RevEngPoint*>& points, BoundingBox bb) + { + assos_points_.push_back(points); + bbox_.push_back(bb); + } + }; + + /// Set edge classification type. + void setEdgeClassificationType(int edge_class_type) + { + edge_class_type_ = edge_class_type; + } + + /// Set point classification type + void setClassificationType(int classification_type) + { + classification_type_ = classification_type; + } + + void setElementaryPreferLevel(int preferlevel) + { + prefer_elementary_ = preferlevel; + } + + void setModelCharacterization(int character) + { + //model_character_ = std::min(ROUGH, std::max(SMOOTH, character)); + model_character_ = std::min(2, std::max(0, character)); + } + + double getInitApproxTol(); + void edgeClassification(); + void curvatureFilter(); + + void initParameters(); + void updateParameters(); + bool recognizeOneSurface(int& ix, int min_point_in, double angtol, + int pass); + void recognizeSurfaces(int min_point_in, int pass); + void recognizeEdges(bool only_curve=false); + bool createBlendSurface(int ix); + void adjustPointRegions(int min_point_in); + + void computeAxisFromCylinder(Point initaxis[3], int min_num, double max_ang, + Point axis[3], int num_points[3]); + + void computeAxisFromPlane(Point initaxis[3], int min_num, double max_ang, + Point axis[3], int num_points[3]); + + void surfaceExtractOutput(int idx, + std::vector<std::vector<RevEngPoint*> > out_groups, + std::vector<HedgeSurface*> prev_surfs); + + bool segmentComposite(int& ix, int min_point_in, double angtol); + bool segmentByPlaneGrow(int ix, int min_point_in, double angtol); + bool segmentByAxis(int ix, int min_point_in); + bool segmentByContext(int ix, int min_point_in, double angtol, bool first); + void growSurface(int& ix, int pass = 1); + void growBlendSurface(int& ix); + void growMasterSurface(int& ix); + + void defineSmallRegionSurfaces(); + + void growSmallRegionSurface(int& ix); + + bool identifySmallRotational(std::vector<RevEngPoint*>& points, + Point midp, Point loc, Point axis, Point Cx, + double ppar1, double ppar2, + std::vector<shared_ptr<ElementarySurface> >& sfs); + + bool identifySmallPlanar(std::vector<RevEngRegion*>& groups, + Point loc, Point axis, Point Cx, + double ppar1, double ppar2, double delta, + std::vector<shared_ptr<ElementarySurface> >& sfs); + + bool identifySmallPlanar(std::vector<RevEngPoint*>& groups, + Point loc, Point axis, Point Cx, + double ppar1, double ppar2, double delta, + std::vector<shared_ptr<ElementarySurface> >& sfs); + + shared_ptr<ElementarySurface> + defineElemSurf(std::vector<RevEngPoint*>& points, std::vector<RevEngPoint*>& in_points, + BoundingBox& bbox, std::vector<RevEngPoint*>& remain); + + void planarAtPlane(shared_ptr<Plane> axis_plane, + std::vector<RevEngPoint*>& points, + std::vector<HedgeSurface*>& sfs, + std::vector<shared_ptr<RevEngRegion> >& plane_sf_reg, + std::vector<shared_ptr<HedgeSurface> >& plane_sf_hedge); + + void integrateInSmallSurfs(std::vector<shared_ptr<RevEngRegion> >& small_sf_reg, + std::vector<RevEngRegion*>& nosf_reg, + std::vector<RevEngRegion*>& include_reg); + + void extractSmallSurfs(SmallSurface& small_surf, + std::vector<shared_ptr<RevEngRegion> >& small_sf_reg, + std::vector<shared_ptr<HedgeSurface> >& small_sf_hedge, + std::vector<RevEngRegion*>& nosf_reg, + std::vector<RevEngPoint*>& non_assigned_pts); + + void doAdaptToAxis(); + + bool axisUpdate(int ix, double max_ang, double angtol); + + void adjustWithMainAxis(std::vector<Point>& axes, std::vector<int>& num_pts); + Point planarFit(std::vector<int>& sf_ix, Point axis); + + Point rotationalFit(std::vector<int>& sf_ix, Point axis, Point Cx, + std::vector<RevEngEdge*>& nopar_edgs); + + void collectAxis(std::vector<SurfaceProperties>& sfprop); + + void computeLocFunc(RevEngPoint* pt, std::vector<RevEngPoint*>& points, + Point& vec1, Point& vec2, double radius); + + int setSmallRegionNumber(); + + void storeParams(std::ostream& os) const; + void readParams(std::istream& is); + void setBoundingBox(); + + void checkConsistence(std::string text) const; + + std::vector<shared_ptr<RevEngEdge> > + defineEdgesBetween(size_t ix1,shared_ptr<ElementarySurface>& surf1, + Point& dir1, size_t ix2, shared_ptr<ElementarySurface>& surf2, + Point& dir2, bool only_curve=false, + double lenlim=-1.0, bool check_common = true); + + shared_ptr<RevEngEdge> + defineOneEdge(size_t ix1, shared_ptr<ElementarySurface>& surf1, + Point& dir1, size_t ix2, + shared_ptr<ElementarySurface>& surf2, Point& dir2, + shared_ptr<CurveOnSurface>& int_cv1, + shared_ptr<CurveOnSurface>& int_cv2, + double width, std::vector<RevEngRegion*>& common_reg, + bool only_curve, bool check_common); + + RevEngPoint* getDistantPoint(shared_ptr<CurveOnSurface>& cv, + double tmin, double tmax, double dd, + double width, + std::vector<RevEngPoint*>& points); + + void extendBlendAssociation(size_t ix); + + bool setBlendEdge(size_t ix); + + double + computeCylinderRadius(std::vector<std::vector<RevEngPoint*> > blend_pts, + double width, const Point& pos, const Point& axis, + const Point& dir1, const Point& dir2); + shared_ptr<Cylinder> + createCylinderBlend(std::vector<std::vector<RevEngPoint*> > blend_pts, + double rad1, const Point& pos, const Point& axis, + const Point& dir1, const Point& dir2, int sgn); + + double + computeTorusRadius(std::vector<std::vector<RevEngPoint*> >& blend_pts, + shared_ptr<CurveOnSurface>& cv, + const Point& locp, const Point& normal, + shared_ptr<ElementarySurface> rotational, + double width, bool plane_out, bool rot_out); + + void getTorusParameters(shared_ptr<ElementarySurface> planar, + shared_ptr<ElementarySurface> rotational, + double radius, int sgn1, int sgn2, double& Rrad, + Point& centre, Point& normal, Point& Cx); + + double + computeTorusRadius(std::vector<std::vector<RevEngPoint*> >& blend_pts, + shared_ptr<CurveOnSurface>& cv, + shared_ptr<ElementarySurface> elem1, + shared_ptr<ElementarySurface> elem2, + double width, bool out1, bool out2, int sgn, + double& d2); + + bool + getTorusParameters(shared_ptr<ElementarySurface> elem1, + shared_ptr<ElementarySurface> elem2, Point pos, + double radius, double d2, bool out1, bool out2, int sgn, + double& Rrad, Point& centre, Point& normal, Point& Cx, + bool check_common = true); + + shared_ptr<Torus> + torusBlend(std::vector<std::vector<RevEngPoint*> >& blend_pts, + std::vector<shared_ptr<CurveOnSurface> >& cvs, + const Point& locp, const Point& normal, + shared_ptr<ElementarySurface> rotational, + double width, bool plane_out, bool rot_out); + + shared_ptr<Torus> + torusBlend(std::vector<std::vector<RevEngPoint*> >& blend_pts, + shared_ptr<CurveOnSurface>& cv, + shared_ptr<ElementarySurface> elem1, + shared_ptr<ElementarySurface> elem2, + double width, bool out1, bool out2, int sgn); + + void setBlendBoundaries(RevEngRegion *reg); + + void equalizeBlendRadii(); + + void equalizeAdjacent(size_t ix1, size_t ix2); + + void updateBlendRadius(size_t ik, double radius); + + bool defineTorusCorner(size_t ix); + + void defineMissingCorner(std::vector<RevEngRegion*>& cand_adj); + + bool createTorusBlend(size_t ix); + + bool suitcaseCorner(std::vector<RevEngRegion*>& adj_blends, + RevEngEdge *rev_edge); + + void extractOutPoints(std::vector<RevEngPoint*>& points, shared_ptr<ParamSurface> surf, + std::vector<int>& cv_ix, + double tol, double angtol, + std::vector<std::vector<RevEngPoint*> >& move2adj, + std::vector<RevEngPoint*>& remain); + + void storeClassified(std::ostream& os) const; + void readClassified(std::istream& is); + + }; + +} // namespace Go + +#endif // _REVENG_H diff --git a/compositemodel/include/GoTools/compositemodel/RevEngEdge.h b/compositemodel/include/GoTools/compositemodel/RevEngEdge.h new file mode 100644 index 00000000..b995cada --- /dev/null +++ b/compositemodel/include/GoTools/compositemodel/RevEngEdge.h @@ -0,0 +1,442 @@ +/* + * Copyright (C) 1998, 2000-2007, 2010, 2011, 2012, 2013 SINTEF ICT, + * Applied Mathematics, Norway. + * + * Contact information: E-mail: tor.dokken@sintef.no + * SINTEF ICT, Department of Applied Mathematics, + * P.O. Box 124 Blindern, + * 0314 Oslo, Norway. + * + * This file is part of GoTools. + * + * GoTools is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * GoTools 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with GoTools. If not, see + * <http://www.gnu.org/licenses/>. + * + * In accordance with Section 7(b) of the GNU Affero General Public + * License, a covered work must retain the producer line in every data + * file that is created or manipulated using GoTools. + * + * Other Usage + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial activities involving the GoTools library without + * disclosing the source code of your own applications. + * + * This file may be used in accordance with the terms contained in a + * written agreement between you and SINTEF ICT. + */ + +#ifndef _REVENGEDGE_H +#define _REVENGEDGE_H + +#include "GoTools/compositemodel/RevEngRegion.h" +#include "GoTools/geometry/CurveOnSurface.h" + +namespace Go +{ + /// Flag indicating type of associated blend surface. Only partially in use: + /// BLEND_NOT_SET = blend surface is expected, NOT_BLEND = sharp edge between + /// surfaces + enum + { + BLEND_NOT_SET, NOT_BLEND, STRAIGHT_BLEND, CIRCULAR_BLEND, OTHER_BLEND + }; + + /** RevEngEdge - Represents an edge between two surfaces associated RevEngRegions. + Information about intersection curve, adjacent regions, possible blend + surfaces/regions and other regions associated to this blend + * + */ + + class RevEngEdge + { + public: + /// Constructor + RevEngEdge(); + + /// Constructor giving the regions whom associated surfaces is intersected + /// to produce this edge + RevEngEdge(RevEngRegion* reg1, RevEngRegion* reg2); + + /// Constructor giving information to produce an associated blend surface + RevEngEdge(int type, RevEngRegion* reg1, + std::vector<shared_ptr<CurveOnSurface> > cvs1, + bool out1, RevEngRegion* reg2, + std::vector<shared_ptr<CurveOnSurface> > cvs2, + bool out2, double radius, double width); + + /// Destructor + ~RevEngEdge(); + + /// Set entity identity. Used in storing of stage (see RevEng) + void setId(int Id) + { + Id_ = Id; + } + + /// Enquire entity identity + int getId() + { + return Id_; + } + + /// Enquire type of blend associated to edge + int getType() + { + return blend_type_; + } + + /// Change first adjacent region and ensure that related information is updated + void setReg1(RevEngRegion *reg); + + /// Change second adjacent region and ensure that related information is updated + void setReg2(RevEngRegion *reg); + + /// Increase the pool of regions associated to a future blend surface + void addBlendRegion(RevEngRegion* reg) + { + blend_regs_.push_back(reg); + } + + /// Increase the pool of regions associated to a future blend surface + void addBlendRegions(std::vector<RevEngRegion*>& regs) + { + blend_regs_.insert(blend_regs_.end(), regs.begin(), regs.end()); + } + + /// Remove all regions associated to a blend surface + void clearBlendRegions() + { + blend_regs_.clear(); + } + + /// Remove one region associated to a blend surface + void removeBlendReg(RevEngRegion* reg) + { + auto it = std::find(blend_regs_.begin(), blend_regs_.end(), reg); + if (it != blend_regs_.end()) + blend_regs_.erase(it); + } + + /// Fetch geometry space curves of intersection curves between adjacent region surfaces + /// Expects one curve + std::vector<shared_ptr<ParamCurve> > getSpaceCurves(); + + /// Number of regions associated to a future blend surface + int numBlendRegs() + { + return (int)blend_regs_.size(); + } + + /// Fetch specified region associated to a future blend surface + RevEngRegion* getBlendReg(int ix) + { + if (ix < 0 || ix >= (int)blend_regs_.size()) + return 0; + else + return blend_regs_[ix]; + } + + /// Fetch all regions associated to a future blend surface + void getAllBlendRegs(std::vector<RevEngRegion*>& blend_regs) + { + if (blend_regs_.size() > 0) + blend_regs.insert(blend_regs.end(), blend_regs_.begin(), + blend_regs_.end()); + } + + /// Fetch adjacent region/surfaces used to create edge + void getAdjacent(RevEngRegion*& reg1, RevEngRegion*& reg2) + { + reg1 = adjacent1_; + reg2 = adjacent2_; + } + + /// Fetch information on how the blend surface should be placed related to the + /// adjacent region surfaces + void getOuterInfo(bool& out1, bool& out2) + { + out1 = outer1_; + out2 = outer2_; + } + + + /// Fetch intersection curves between adjacent region surfaces + /// \param first The curve (parameter curve) to select + /// Expects one curve + void getCurve(std::vector<shared_ptr<CurveOnSurface> >& cvs, bool first=true) + { + if (first && cvs1_.size() > 0) + cvs.insert(cvs.end(), cvs1_.begin(), cvs1_.end()); + else if ((!first) && cvs2_.size() > 0) + cvs.insert(cvs.end(), cvs2_.begin(), cvs2_.end()); + } + + /// Get endpoints of intersection curve in geometry space + void getCrvEndPoints(Point& pos1, Point& pos2); + + /// Fetch the distance from the intesection curve where points related to the blend + /// surface is to be fetched. This distance is typically larger than the final size + /// of the blend surface to make sure to get sufficient information to compute the blend. + double getDistance() + { + return distance_; + } + + /// Fetch estimate of blend radius + double getRadius() + { + return radius_; + } + + /// Set estimate of blend radius + void setRadius(double radius) + { + radius_ = radius; + } + + /// The number of times an associated region surface is changed. Indicates a need for + /// updating the edge + int getSurfChangeCount() + { + return surfchangecount_; + } + + /// An adjacent region surface has been changed + void increaseSurfChangeCount() + { + surfchangecount_++; + } + + /// The edge is updated. Reset change count + void resetSurfChangeCount() + { + surfchangecount_ = 0; + } + + /// The number of times an associated region is increased with more points. Indicates + /// a possibility for a longer edge + int getExtendCount() + { + return extendcount_; + } + + /// An adjacent region has been extended with more points + void increaseExtendCount() + { + extendcount_++; + } + + /// The edge is updated. Reset edge count + void resetExtendCount() + { + extendcount_ = 0; + } + + /// Set associated blend surface + void setBlendRegSurf(RevEngRegion* blend) + { + defined_blend_ = blend; + } + + /// Fetch associated blend surface + RevEngRegion* getBlendRegSurf() + { + return defined_blend_; + } + + /// Closest point between the intersection curves and the point pos + void closestPoint(const Point& pos, double& par, Point& close, + double& dist); + + /// Closest point between specified intersection curve and the point pos + void closestPoint(const Point& pos, double& par, Point& close, + double& dist, int& ix); + + /// Update intersection curve information (CurveOnSurface) when the adjacent + /// region reg has been associated another surface new_surf + void replaceSurf(RevEngRegion* reg, shared_ptr<ParamSurface>& new_surf, + double tol); + + /// Check consistency between geometry and parameter space curves and fix + /// if necessary + void fixMismatchCurves(double tol); + + /// Remove intersection curves + void eraseCurves() + { + cvs1_.clear(); + cvs2_.clear(); + } + + /// Remove information about one adjacent regions + void eraseAdjacent(RevEngRegion *adj) + { + if (adjacent1_ == adj) + adjacent1_ = 0; + else if (adjacent2_ == adj) + adjacent2_ = 0; + } + + /// Replace intersection curves + void replaceCurves(std::vector<shared_ptr<CurveOnSurface> > int_cvs1, + std::vector<shared_ptr<CurveOnSurface> > int_cvs2) + { + cvs1_.clear(); + cvs2_.clear(); + cvs1_.insert(cvs1_.end(), int_cvs1.begin(), int_cvs1.end()); + cvs2_.insert(cvs2_.end(), int_cvs2.begin(), int_cvs2.end()); + } + + /// Check if the specified edge endpoint lies at the seam of a closed + /// adjacent region surface + int closedSfAtEnd(double tol, double& par, Point& pos, bool at_start); + + /// Check if the edge is closed with respect to the tolerance tol + bool isClosed(double tol); + + /// Check if this edge and the edge other is adjacent and in that case + /// return the parameter values of the joint + bool isAdjacent(RevEngEdge* other, double tol, double& par1, double& par2); + + double startparam() + { + return cvs1_[0]->startparam(); + } + + double endparam() + { + return cvs1_[cvs1_.size()-1]->endparam(); + } + + /// Evaluate edge + Point point(double par); + + /// Append the edge other to this one. Check if the conditions allow append, turn + /// curves if nesessary and update associated information + bool append(RevEngEdge *other, double tol); + + /// Check if the parameter curve is missing for any intersection curve + int missingParCrv(); + + /// Split edge at the seam of an adjacent region surface and update associated + /// information accordingly. + /// \param added_edgs New edges due to split. As the adjacent region surfaces may have + /// more than one seam more than one new edge may be created + /// \param added_regs If a region associated to a future blend surface is divided + /// between two edges + /// \param added_sfs Not used + void splitAtSeam(double tol, std::vector<shared_ptr<RevEngEdge> >& added_edgs, + std::vector<shared_ptr<RevEngRegion> >& added_regs, + std::vector<shared_ptr<HedgeSurface> >& added_sfs); + + /// Update the edge if and adjacent region is changed and extendCurve is + /// not applied + bool updateCurve(double int_tol, double tol, double len); + + /// Recompute intersection curve if the adjacent regions are extended with + /// more points. Keep parts of the associated information + /// \param int_tol Tolerance used in intersection + /// \param tol Approximation tolerance + /// \param anglim Used in estimation of edge extent and to compute angular tolerance + /// \param len Indicates size of environment + /// \param lenlim Minimum length of intersection curve + /// \param blendlim Upper limit of with of blend surface + /// \param added_regions If regions are split to be associated a future blend surface + /// \param extract_groups If regions are split to maintain connectivity + /// \param out_sfs Surface to remove since the associated region has been too small + bool + extendCurve(double int_tol, double tol, double anglim, + double len, double lenlim, double blendlim, + std::vector<shared_ptr<RevEngRegion> >& added_regions, + std::vector<std::vector<RevEngPoint*> >& extract_groups, + std::vector<HedgeSurface*>& out_sfs); + + /// Define trimming curves from edges that will not lead to a blend surface. + /// Associate regions connected to this blend surface to the adjacent regions as + /// appropriate. Freed regions and eventual associated surfaces are reported in + /// out_regs and out_sfs + void setTrimCurves(double tol, double angtol, + std::vector<RevEngRegion*>& out_regs, + std::vector<HedgeSurface*>& out_sfs); + + /// Check if the edge other is contained in this (coincidence) + bool contains(RevEngEdge *other, double tol); + + /// Include the edge other in this (presupposes coincidence) and update parameters + /// accordingly + bool integrate(RevEngEdge *other); + + /// Store edge to file + void store(std::ostream& os); + + /// Read edge from file and collect information necessary to recreate the data structure + void read(std::istream& is, int& reg_id1, int& reg_id2, + int& reg_id3, std::vector<int>& blend_id); + + private: + /// Unique id for edge. Used in storing and reading data structure to and from file + int Id_; + + /// First regions where the region surface is intersected to produce this edge + RevEngRegion* adjacent1_; + + /// Second regions where the region surface is intersected to produce this edge + RevEngRegion* adjacent2_; + + /// Blend surface associated to the intersection curve between region surfaces + /// represented in this edge + RevEngRegion* defined_blend_; + + /// Intersection curve with parameter curve in region surface one + std::vector<shared_ptr<CurveOnSurface> > cvs1_; + + /// Intersection curve with parameter curve in region surface two + std::vector<shared_ptr<CurveOnSurface> > cvs2_; + + /// Regions associated to a future blend surface corresponding to this edge + std::vector<RevEngRegion*> blend_regs_; + + /// Type of blend: currently BLEND_NOT_SET or NOT_BLEND + int blend_type_; + + /// The distance from the interection curve in which to search for points associated + /// to the blend surface + double distance_; + + /// Estimate of blend radius + double radius_; + + /// How a blend surface will be placed relative to the outside of region surface one + bool outer1_; + + /// How a blend surface will be placed relative to the outside of region surface two + bool outer2_; + + /// Whether any of the adjacent region surfaces is changed + int surfchangecount_; + + /// Whether any of the adjacent regions is extended with more points + int extendcount_; + + shared_ptr<RevEngEdge> doSplit(size_t ix, int side, double par, double tol, + std::vector<shared_ptr<RevEngRegion> >& added_regs, + std::vector<shared_ptr<HedgeSurface> >& added_sfs); + + void updateParCurve(RevEngRegion* adj, double int_tol); + + }; +} + +#endif diff --git a/compositemodel/include/GoTools/compositemodel/RevEngPoint.h b/compositemodel/include/GoTools/compositemodel/RevEngPoint.h new file mode 100644 index 00000000..744fec54 --- /dev/null +++ b/compositemodel/include/GoTools/compositemodel/RevEngPoint.h @@ -0,0 +1,635 @@ +/* + * Copyright (C) 1998, 2000-2007, 2010, 2011, 2012, 2013 SINTEF ICT, + * Applied Mathematics, Norway. + * + * Contact information: E-mail: tor.dokken@sintef.no + * SINTEF ICT, Department of Applied Mathematics, + * P.O. Box 124 Blindern, + * 0314 Oslo, Norway. + * + * This file is part of GoTools. + * + * GoTools is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * GoTools 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with GoTools. If not, see + * <http://www.gnu.org/licenses/>. + * + * In accordance with Section 7(b) of the GNU Affero General Public + * License, a covered work must retain the producer line in every data + * file that is created or manipulated using GoTools. + * + * Other Usage + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial activities involving the GoTools library without + * disclosing the source code of your own applications. + * + * This file may be used in accordance with the terms contained in a + * written agreement between you and SINTEF ICT. + */ + +#ifndef _REVENGPOINT_H +#define _REVENGPOINT_H + +#include "GoTools/compositemodel/ftPointSet.h" +//#include "GoTools/compositemodel/RevEngRegion.h" +#include "GoTools/utils/Array.h" +#include "GoTools/utils/Point.h" +#include "GoTools/utils/DirectionCone.h" + +namespace Go +{ + class RevEngRegion; + + /** RevEngPoint - A triangulation vertex enhanced with with information such as estimated + surface normal and curvature, classification flags and associated functionality. + A RevEngPoint knows which RevEngRegion it belongs to, if any. The reverse engineering + functionality where RevEngPoint participates is run from RevEng. + * + */ + // Enumerations representing classification results + + /// Edge classification based on covariance. Not used + enum + { + PCA_EDGE_UNDEF, PCA_NOT_EDGE, PCA_CLOSE_EDGE, PCA_EDGE + }; + + /// Edge classification based on curvature radius. Used + enum + { + C1_EDGE_UNDEF, C1_NOT_EDGE, C1_CLOSE_EDGE, C1_EDGE + }; + + enum + { + C2_EDGE_UNDEF, C2_NOT_EDGE, C2_CLOSE_EDGE, C2_EDGE + }; + + /// Point classification based on covariance. Not used + enum + { + PCA_UNDEF, PCA_PLANAR, PCA_LINEAR, PCA_OTHER + }; + + /// Point classification based on curvature. Used + enum + { + C1_UNDEF, C1_PEAK, C1_RIDGE, C1_SRIDGE, C1_NONE, C1_FLAT, C1_MINSURF, C1_PIT, C1_VALLEY, C1_SVALLEY + }; + + /** Subclass of ftSamplePoint; Enhanced point for use in reverse engineering + */ + class RevEngPoint : public ftSamplePoint + { + + public: + /// Constructor + RevEngPoint(); + + /// Constuctor given point position + /// \param bnd Boundary information. Inherited from ftSamplePoint. Not used + RevEngPoint(Vector3D xyz, int bnd); + + /// Destructor + virtual ~RevEngPoint(); + + /// Compute normal based on the triangles meeting in the vertex + /// \param lim Avoid very long triangle edges + void computeTriangNormal(double lim); + + /// Set eigen vector and values in point + void addCovarianceEigen(Point& eigen1, double lambda1, Point& eigen2, + double lambda2, Point& eigen3, double lambda3); + + /// Set normal and curvature information computed from expressing a group of points + /// in the vicinity of the current in the coordinate system given by the eigen vector + /// and approximate the points with a Bezier function. Surface normal minimum and + /// maximum principal curvature vectors and values are computed as well as + /// the distance from this point to the function and the average distance for all points + /// in the group + void addLocFuncInfo(Point& norm, Point& mincvec, double minc, Point& maxcvec, + double maxc, double currdist, double avdist); + + /// Enquire triangulation normal + Point getTriangNormal() + { + Point zero(0.0,0.0,0.0); + return normalcone_.greaterThanPi() ? zero : + normalcone_.centre(); + } + + /// Enquire the cone angle of a cone surrounding the surface normal of all + /// triangles meeting in this vertex + double getTriangAngle() + { + return normalcone_.greaterThanPi() ? 2.0*M_PI : normalcone_.angle(); + } + + /// Enquire the average length of triangle edges meeting in this vertex + double getMeanEdgLen(); + + /// Enquire the average length of triangle edges meeting in this vertex excluding + /// edges with a length larger than maxlen + double getMeanEdgLen(double maxlen); + + /// Enquire the normal computed from a local function approximation + const Point& getLocFuncNormal() + { + return LocFuncnormal_; + } + + /// Turn the normal computed from a local function approximation + void turnLocFuncNorm() + { + LocFuncnormal_ *= -1; + } + + + /// Enquire first eigen vector + const Point& getPCAEigen1() + { + return eigen1_; + } + + /// Enquire normal given by covariance, e.g. the third eigen vector + const Point& getPCANormal() + { + return eigen3_; + } + + /// Turn direction of the coordinate system given by eigen vector + void turnPCA() + { + eigen2_ *= -1; + eigen3_ *= -1; + } + + + + /// Traverse the triangulation and fetch points belonging to a given region, if given, + /// within the sphere with radius radius from this vertex + /// \param min_nmb Minimum number of points required. The radius is + /// increased if necessary to reach this number of points + /// \param max_nmb When this number of points is reached, the search is stopped + void fetchClosePoints2(double radius, int min_nmb, int max_nmb, + std::vector<RevEngPoint*>& nearpts, + RevEngRegion *region = 0); + + /// Fetch points belonging to the specified region connected through triangle edges, + /// starting from current. Stop when max_nmb points are reached + void fetchConnected(RevEngRegion *region, int max_nmb, + std::vector<RevEngPoint*>& group); + + /// Fetch points marked with mark connected through triangle edges, + /// starting from current. + void fetchConnectedMarked(int mark, + std::vector<RevEngPoint*>& group); + + /// Indicate that the points has been visited in a traversal + void setVisited() + { + visited_ = 1; + } + + /// A traversal is finished. Reset flag + void unsetVisited() + { + visited_ = 0; + } + + /// Check if a point has been visited in a traversal + bool visited() + { + return (visited_ > 0); + } + + /// Indicate that the point has been moved from one region to another. + void setMoved() + { + moved_ = 1; + } + + /// Reset move flag + void unsetMoved() + { + moved_ = 0; + } + + /// Check if a ponit has been moved between regions + bool moved() + { + return (moved_ > 0); + } + + /// The eigen vectors and values are averaged between several computations. + /// The number of computations are returned + int nmbEigen() + { + return nmb_eigen_; + } + + /// The results of the computation of normal and curvature by local funcations are + /// averaged between several computations. The number of computations are returned + int nmbLocFunc() + { + return nmb_locfunc_; + } + + /// Enquire maximum principal curvature value + double maxPrincipalCurvature() + { + return kmax_; + } + + /// Enquire maximum principal curvature vector + Point maxCurvatureVec() + { + return kvecmax_; + } + + /// Enquire miniumum principal curvature value + double minPrincipalCurvature() + { + return kmin_; + } + + /// Enquire miniumum principal curvature vector + Point minCurvatureVec() + { + return kvecmin_; + } + + /// Enquire Gauss curvature + double GaussCurvature() + { + return gausscurv_; + } + + /// Enquire mean curvature + double meanCurvature() + { + return meancurv_; + } + + /// Gauss and mean curvature are smoothed to get less fragmented segmentation. + /// Enquire previous value of Gauss curvature + double GaussCurvature0() + { + return gausscurv0_; + } + + /// Gauss and mean curvature are smoothed to get less fragmented segmentation. + /// Enquire previous value of mean curvature + double meanCurvature0() + { + return meancurv0_; + } + + /// Set mean curvature. Used in smoothing of mean curvature + void setMeanCurvature(double mean) + { + meancurv_ = mean; + } + + /// Set Gauss curvature. Used in smoothing of Gauss curvature + void setGaussCurvature(double Gauss) + { + gausscurv_ = Gauss; + } + + /// Update curvature values. Used in iteration for smoothing Gauss and mean curvature + void updateCurvature() + { + meancurv0_ = meancurv_; + gausscurv0_ = gausscurv_; + } + + double getCurvedness() + { + return curvedness_; + } + + + /// Set edge status in point using curvature radius + void setEdgeClassification(int c1_edge) + { + edge_[0] = PCA_EDGE_UNDEF; + edge_[1] = c1_edge; + edge_[2] = C2_EDGE_UNDEF; + } + + /// Set point classification using mean and Guass curvature + void setClassification(int ctype) + { + surf_[0] = PCA_UNDEF; + surf_[1] = ctype; + } + + /// Check if a point is classified as edge. edge_class_type is expected to be C1_EDGE + bool isEdge(int edge_class_type) + { + if (edge_class_type == 1) + return (edge_[0] == PCA_EDGE); + else if (edge_class_type == 2) + return (edge_[1] == C1_EDGE); + else if (edge_class_type == 3) + return (edge_[2] == C2_EDGE); + else + return false; + } + + /// Check if a point near being classified as edge. edge_class_type is expected to be C1_EDGE + bool closeEdge(int edge_class_type) + { + if (edge_class_type == 1) + return (edge_[0] >= PCA_CLOSE_EDGE); + else if (edge_class_type == 2) + return (edge_[1] >= C1_CLOSE_EDGE); + else if (edge_class_type == 3) + return (edge_[2] >= C2_CLOSE_EDGE); + else + return false; + } + + /// Check if a point is different from an edge. edge_class_type is expected to be C1_EDGE + bool notEdge(int edge_class_type) + { + if (edge_class_type == 1) + return (edge_[0] <= PCA_NOT_EDGE); + else if (edge_class_type == 2) + return (edge_[1] <= C1_NOT_EDGE); + else if (edge_class_type == 3) + return (edge_[2] <= C2_NOT_EDGE); + else + return true; + } + + /// Check if a point is classified as edge, but lacks other edge points + /// in its vicinity + bool isolatedEdge(int edge_class_type, int nmb, bool close); + + /// Unset edge information in point + void setEdgeUndef() + { + edge_[0] = PCA_EDGE_UNDEF; + edge_[1] = C1_EDGE_UNDEF; + edge_[2] = C2_EDGE_UNDEF; + } + + /// Get distance between point and the local function used to compute normal and + /// curvature information + double getPointDistance() + { + return ptdist_; + } + + /// Get average distance between local point sets and the function used to compute normal + /// and curvature information + double getAveragePointDistance() + { + return avdist_; + } + + /// Enquire the point classification with respect to expected surface type + int surfaceClassification(int classification_type) const; + + /// A point classified as edge is reclassified as near edge if the triangles meeting + /// in the point don't indicate an edge + void adjustWithTriangNorm(double anglim); + + /// Check if the point is assigned a region + bool hasRegion() + { + return (region_ != 0); + } + + /// Enquire the region assigned to the point + RevEngRegion* region() + { + return region_; + } + + /// Set region in point + void setRegion(RevEngRegion* region) + { + region_ = region; + } + + /// Unset region information + void unsetRegion() + { + region_ = 0; + } + + /// Unset accuracy and parameter information with respect to the surface + /// approximating the points in the associated region + void unsetSurfInfo() + { + sfdist_ = -1.0; + sfang_ = -1.0; + uv_ = Vector2D(0.0, 0.0); + } + + /// Fetch regions different from the region of this point associated to the neighbouring + /// points of this point + void adjacentRegions(std::vector<RevEngRegion*>& adj) const; + + /// Check if any neighbour is associated the region reg + bool nextToRegion(RevEngRegion *reg); + + /// Return classification of of point using Gauss and mean curvature + int C1_surf() + { + return surf_[1]; + } + + /// Mark point as outlier + void setOutlier() + { + outlier_ = true; + } + + /// Reset outlier information + void unsetOutlier() + { + outlier_ = false; + } + + /// Check if a point is classified as outlier + bool isOutlier() + { + return outlier_; + } + + /// The number of neighbours having the same classification as this point + int nmbSameClassification(int classification_type) const; + + /// Record the distance between this point and the surface approximating the points + /// of the associated region as well as the angular difference between surface normal + /// and normal in point (least angle with respect to triangulation normal and local + /// function normal) + void setSurfaceDist(double dist, double ang) + { + sfdist_ = dist; + sfang_ = ang; + } + + /// Enquire distance to approximating surface + double getSurfaceDist() + { + return sfdist_; + } + + /// Enquire distance and normal difference with respect to approximating surface + void getSurfaceDist(double& dist, double& ang) + { + dist = sfdist_; + ang = sfang_; + } + + /// Check if any neighbouring vertex is associated the region reg + bool isNeighbour(RevEngRegion* reg) const; + + /// Check if this vertex and pt are neighbours + bool isNeighbour(RevEngPoint* pt) const; + + /// Fetch regions associated to neighbouring points that are associated a surface + std::vector<RevEngRegion*> adjacentRegsWithSurf() const; + + /// Increase the number of moves between regions performed by this point + void addMove() + { + nmb_move_++; + } + + /// Enquire the number of moves between regions performed by this point + /// (not complete information) + int numMove() + { + return nmb_move_; + } + + /// Fetch adjacent regions to this point and the closest point in those + /// regions. Distant regions/points are excluded (distance depends on mean_edge_len) + void getAdjInfo(double mean_edge_len, std::vector<RevEngRegion*>& adj_reg, + std::vector<RevEngPoint*>& adj_pt); + + /// Fetch regions associated to neighbouring points + std::vector<RevEngRegion*> getAdjacentRegions() const; + + + /// Number of different regions associated to neighbouring points + int numAdjacentRegions() const; + + /// Include point in adjacent regions if the distance to this region is suffiently + // small and the point normal information is consistent + bool mergeWithAdjacent(double mean_edge_len); + + /// Set flag used in region growing and identification of connected groups + void setMarkIx(int ix) + { + mark_ix_ = ix; + } + + /// Unset flag used in region growing and identification of connected groups + void unsetMarkIx() + { + mark_ix_ = -1; + } + + /// Enquire flag used in region growing and identification of connected groups + int getMarkIx() + { + return mark_ix_; + } + + /// Store enhanced vertex information to file + void store(std::ostream& os) const; + + /// Read enhanced vertex information from file. Return information about neighbouring vertices + void read(std::istream& is, vector<int>& next_ix); + + private: + /// Average length of edges meeting in this vertex + double avedglen_; + + /// Eigenvectors of covariance matrix + Point eigen1_, eigen2_, eigen3_; + + /// Eigenvalues of covariance matrix. lambda1_>= lambda2_ >= lambda3_ + double lambda1_, lambda2_, lambda3_; + + /// Normal and principal curvature vectors computed from local function approximation + Point LocFuncnormal_, kvecmin_, kvecmax_; + + /// Principal curvatures computed from local function approximation + double kmin_, kmax_; + + /// Distance to local function + double ptdist_, avdist_; + + /// Number of point groups averaged to compute eigen vector/values, normal and + /// curvature information + int nmb_eigen_, nmb_locfunc_; + + /// Span of surface normals computed from triangulation + DirectionCone normalcone_; + + /// Previous and current version of mean curvature + double meancurv0_, meancurv_; + + /// Previous and current version of Gauss curvature + double gausscurv0_, gausscurv_; + + /// Curvedness computed from principal curvatures. Not used + double curvedness_; + + /// Parameters corresponding to classification results + /// Results of edge classification. Sequence: Surface variation (PCA), curvature (C1), + /// curveness (C2) + int edge_[3]; + + /// Results of surface classification. Sequence: PCA, curvature (C1), + int surf_[2]; // + + /// Group (segment) of classified points + RevEngRegion* region_; + + /// Outlier flag + bool outlier_; + + /// Distance beteen point and surface approximating associated region + double sfdist_; + + /// Angle between estimated normal in point and surface normal + double sfang_; + + /// Number of times this point has been moved between region. Uncomplete information + int nmb_move_; + + /// Flags mainly used in traversal + mutable int visited_; + mutable int moved_; + mutable int mark_ix_; + + // Traverse the triangulation and fetch points within the sphere with + // radius radius from this vertex + Point fetchClosePoints(double radius, int min_nmb, int max_nmb, + std::vector<Point>& nearpts); + void getNearby(Vector3D xyz, double radius, int max_nmb, + std::vector<RevEngPoint*>& near, + RevEngRegion *region = 0); + }; +} + +#endif diff --git a/compositemodel/include/GoTools/compositemodel/RevEngRegion.h b/compositemodel/include/GoTools/compositemodel/RevEngRegion.h new file mode 100644 index 00000000..b2831f97 --- /dev/null +++ b/compositemodel/include/GoTools/compositemodel/RevEngRegion.h @@ -0,0 +1,1856 @@ +/* + * Copyright (C) 1998, 2000-2007, 2010, 2011, 2012, 2013 SINTEF ICT, + * Applied Mathematics, Norway. + * + * Contact information: E-mail: tor.dokken@sintef.no + * SINTEF ICT, Department of Applied Mathematics, + * P.O. Box 124 Blindern, + * 0314 Oslo, Norway. + * + * This file is part of GoTools. + * + * GoTools is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * GoTools 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with GoTools. If not, see + * <http://www.gnu.org/licenses/>. + * + * In accordance with Section 7(b) of the GNU Affero General Public + * License, a covered work must retain the producer line in every data + * file that is created or manipulated using GoTools. + * + * Other Usage + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial activities involving the GoTools library without + * disclosing the source code of your own applications. + * + * This file may be used in accordance with the terms contained in a + * written agreement between you and SINTEF ICT. + */ + +#ifndef _REVENGREGION_H +#define _REVENGREGION_H + +#include "GoTools/compositemodel/RevEngPoint.h" +#include "GoTools/compositemodel/ImplicitApprox.h" +#include "GoTools/utils/BoundingBox.h" +#include "GoTools/geometry/ClassType.h" +//#include "GoTools/compositemodel/HedgeSurface.h" +#include <set> + + +namespace Go +{ + class HedgeSurface; + class ftEdge; + //class RevEngPoint; + class Circle; + class SplineCurve; + class CurveOnSurface; + class Plane; + class Cylinder; + class Sphere; + class Cone; + class Torus; + class SplneSurface; + class RevEngEdge; + + /// Method to classify points (vertices). Default and currently the only choice: CLASSIFICATION_CURVATURE + enum + { + CLASSIFICATION_UNDEF, CLASSIFICATION_CURVATURE, CLASSIFICATION_SHAPEINDEX, CLASSIFICATION_POINTASSOCIATION + }; + + /// Method used in edge classification. Default and currently the only choice: CURVATURE_EDGE + enum + { + TRIANGULATION_EDGE, PCATYPE_EDGE, CURVATURE_EDGE, CNESS_EDGE, RPFAC_EDGE + }; + + /// Preference for elementary. Default and recommended choice: ALWAYS_ELEM + enum + { + ALWAYS_ELEM, PREFER_ELEM, BEST_ACCURACY + }; + + /// Surface flag. Quality of approximation. + /// ACCURACY_OK: Requirements met for distance between points and surface and angle between normals + /// ANGULAR_DEVIATION: Requirements met for distance between points and surface + /// PROBABLE_HELIX: As for ANGULAR_DEVIATION in the cylinder and cone case + /// ACCURACY_POOR: Approximation accuracy not met, but the surface is relatively close to the points + /// NOT_SET: No surface or large distance + enum + { + ACCURACY_OK, ANGULAR_DEVIATION, PROBABLE_HELIX, ACCURACY_POOR, NOT_SET + }; + + /// Surface history. Whether or not the surface is modified after first computation + enum + { + INITIAL, AXIS_ADAPTED, ADJACENT_ADAPTED + }; + + /// Nessecary information to create a swept spline surface. Currently disabled + struct SweepData + { + int type_; // Linear = 1, rotational = 2, cylinderlike = 3, conelike = 4 + shared_ptr<SplineCurve> profile_; + Point location_; + Point added_info_; + double radius_; + double angle_; + double maxdist_; + double avdist_; + int num_in_; + + SweepData(int type, shared_ptr<SplineCurve> profile, Point location, + Point info2, double maxdist, double avdist, int num_in, + double radius = -1.0, double angle = 0.0) + { + type_ = type; + profile_ = profile; + location_ = location; + added_info_ = info2; + maxdist_ = maxdist; + avdist_ = avdist; + num_in_ = num_in; + radius_ = radius; + angle_ = angle; + } + }; + + struct SegmentData + { + int type_; // Around axis = 1 + Point loc_; + Point axis_; + double min_dist_; + double max_dist_; + + SegmentData(int type, Point& loc, Point& axis, double mind, double maxd) + { + type_ = type; + loc_ = loc; + axis_ = axis; + min_dist_ = mind; + max_dist_ = maxd; + } + }; + + /** RevEngRegion - Point groups after segmenting a triangulated surface in regions believed + to be appropriate for representaton by one CAD type surface. The regions are dynamic, points + are removed and added as appropriate. Class entities are primarily accessed by RevEng, but + also from RevEngEdge, RevEngPoint and HedgeSurface + * + */ + + class RevEngRegion + { + public: + /// Constructor + RevEngRegion(int edge_class_type); + + RevEngRegion(int classification_type, int edge_class_type); + + /// Constructor given a group of RevEngPoints + RevEngRegion(int classification_type, int edge_class_type, + std::vector<RevEngPoint*>& points); + + /// Destructor + ~RevEngRegion(); + + /// Set entity identity. Used in storing of stage (see RevEng) + void setId(int Id) + { + Id_ = Id; + } + + /// Enquire entity identity + int getId() + { + return Id_; + } + + /// Enquire type + int getClassificationType() + { + return classification_type_; + } + + int getEdgeClassificationType() + { + return edge_class_type_; + } + + /// Check if the group is compatible with a surface type. NB! Not stable information + bool isCompatible(ClassType classtype, int sfcode); + + /// Extend group with one point + void addPoint(RevEngPoint* point); + + /// Extend group with points. + /// NB! The group must be associated a surface + /// NB! No testing on whether the points actually belongs to this group. + /// Accuracy statistics is computed + bool addPointsToGroup(std::vector<RevEngPoint*>& points, + double tol, double angtol, bool compute_accuracy = true); + + /// Remove one point. NB! Leaves overview information invalid. + void removePoint(RevEngPoint* point); + + /// Extend current region with the points of another region. Update class + /// parameters + /// \param dist_ang If given: update new points with distance to surface and angular + /// deviation between normals + void addRegion(RevEngRegion* reg, + std::vector<std::pair<double, double> >& dist_ang, + double maxd=0.0, double avd=0.0, int num_inside=-1, + int num_inside2=-1); + + /// Update class parameters dependent on point properties + void updateInfo(double tol=-1.0, double angtol=-1.0); + + /// Extend region with adjacent points having the same classification + void collect(RevEngPoint *pt, RevEngRegion* prev=0); + + /// Enquire number of points in region + int numPoints() + { + return (int)group_points_.size(); + } + + /// Get specified point + RevEngPoint* getPoint(int ix) + { + if (ix < 0 || ix >= (int)group_points_.size()) + return 0; + else + return group_points_[ix]; + } + + /// Iterator to start of points in region + std::vector<RevEngPoint*>::iterator pointsBegin() + { + return group_points_.begin(); + } + + /// Iterator past points in region + std::vector<RevEngPoint*>::iterator pointsEnd() + { + return group_points_.end(); + } + + /// Return all points + std::vector<RevEngPoint*> getPoints() + { + return group_points_; + } + + /// Return bounding box surrounding all points + const BoundingBox& getBbox() + { + return bbox_; + } + + /// Return bounding box surrounding the parameter points corresponding to the + /// points. Only if the region is associated a surface + BoundingBox getParameterBox(); + + /// Enquire the fraction of LocFunc normals that is closer to the average LocFunc normal + /// in the region than the angular tolerance (used to identify possible planar regions) + double getFracNorm() + { + return frac_norm_in_; + } + + /// Extract a sub group of points that can be approximated by a plane and compute the plane + /// \param mainaxis Local coordinate system for model + /// \param tol Approximation tolerance + /// \param plane_pts Extracted points + /// \param plane_out Computed plane (if a sufficient number of points are found) + void growLocalPlane(Point mainaxis[3], double tol, + std::vector<RevEngPoint*>& plane_pts, + shared_ptr<Plane>& plane_out); + + /// If the region is associated a plane, a cylinder or a cone, extend the point group + /// with points from adjacent regions if feasible. It is ensured that all affected + /// regions are connected + /// \param mainaxis Local coordinate system for model + /// \param tol Approximation tolerance + /// \param grown_regions Regions completely absorbed in the current + /// \param adj_surfs Surfaces associated with the grown regions + /// \param added_groups Connected groups of points extracted from adjacent regions + /// in order to maintain connectivity for these regions + void growPlaneOrCyl(Point mainaxis[3], int min_pt_reg, + double tol, double angtol, + std::vector<RevEngRegion*>& grown_regions, + std::vector<HedgeSurface*>& adj_surfs, + std::vector<std::vector<RevEngPoint*> >& added_groups); + + /// Extract points with a significant distance to the surface and a large angular deviation + /// \param added_groups Connected sub groups of removed points + void removeLowAccuracyPoints(int min_pt_reg, double tol, double angtol, + std::vector<std::vector<RevEngPoint*> >& added_groups); + + /// Include adjacent region is current provided that current is associated with + /// a surface and that the accuracy is sufficient. Accuracy towards surface is computed + /// \param adj Region to include + /// \param mainaxis Local coordinate system for model + /// \param tol Approximation tolerance + /// \param angtol Angular tolerance + /// \param grown_regions Region absorbed in the current + /// \param adj_surfs Surface associated with the grown region + /// \param return Whether or not the region is included + bool includeAdjacent(RevEngRegion* adj, Point mainaxis[3], + double tol, double angtol, + std::vector<RevEngRegion*>& grown_regions, + std::vector<HedgeSurface*>& adj_surfs); + + /// Grow current region with adjacent regions. Current region must be associated + /// with a surface and the accuracy must be sufficient + /// \param mainaxis Local coordinate system for model + /// \param min_pt_reg Associated with surface flag. Not used + /// \param tol Approximation tolerance + /// \param angtol Angular tolerance + /// \param grown_regions Regions absorbed in the current. To be removed in RevEng + /// \param adj_surfs Surfaces associated with the grown regions + /// \param adj_edgs Surfaces associated with the grown regions + void growWithSurf(Point mainaxis[3], int min_pt_reg, + double tol, double angtol, + std::vector<RevEngRegion*>& grown_regions, + std::vector<HedgeSurface*>& adj_surfs, + std::vector<RevEngEdge*>& adj_edgs, + bool use_base=false); + + /// Grow current region associated with a blend surface with adjacent regions not associated + /// any surface. The accuracy must be sufficient + void growBlendSurf(std::vector<RevEngRegion*>& next_blend, double tol, + double angtol, std::vector<RevEngRegion*>& grown_regions, + std::vector<std::vector<RevEngPoint*> >& added_regions); + + /// Check potential accuracy of integrating the region other into current. + /// Current must be associated a surface + int getGrowAccuracy(RevEngRegion *other, double tol, + double angtol, double& maxdist, + double& avdist, int& num_in, int& num2_in, + double& maxdist2, double& avdist2, int& num_in2, + int& num2_in2, std::vector<double>& parvals, + std::vector<std::pair<double,double> >& distang); + + /// If feasible, merge adjacent regions without an associated surface into current. + /// Current is not expected to have an associated surface. The combined regions must + /// be possible to approximate with a plane + bool mergePlanarReg(double zero_H, double zero_K, double tol, + Point mainaxis[3], + std::vector<RevEngRegion*>& grown_regions); + + /// Include adjacent regions with the same type of associated surface into current + /// if the accuracy is sufficient. The current surface may be updated + void mergeAdjacentSimilar(double tol, double angtol, + std::vector<RevEngRegion*>& grown_regions, + std::vector<HedgeSurface*>& adj_surfs, + std::vector<RevEngEdge*>& adj_edgs); + + /// Try to approximate the region points with a plane, a cylinder or a cone. + /// If a surface is recognized will deviant points be extracted + void + initPlaneCyl(int min_point, int min_pt_reg, + double tol, double angtol, Point mainaxis[3], + double zero_H, double zero_K, + std::vector<shared_ptr<HedgeSurface> >& hedgesfs, + std::vector<vector<RevEngPoint*> >& out_groups, + std::vector<RevEngPoint*>& single_pts, bool& repeat); + + /// Not connected parts of the region is extracted and split into + /// connected sub groups + void splitRegion(std::vector<std::vector<RevEngPoint*> >& separate_groups); + + /// Split region with planar points according to the direction of the point normals. + /// To divide the region into groups feasible for being represented by planes with + /// varying normal + void splitPlanar(double lim_cone, int min_point_reg, + std::vector<std::vector<RevEngPoint*> >& other_groups, + std::vector<RevEngPoint*>& single); + + /// Include adjacent regions into current if the accuracy is sufficient. The current surface + /// is not updated + void joinToCurrent(double tol, double angtol, int small_lim, + std::vector<RevEngRegion*>& adapted_regions); + + /// Merge adjacent regions if consistent. The regions are not associated a surface. + /// Time consuming and currently not in use + void joinRegions(Point mainaxis[3], double approx_tol, double anglim, + std::vector<RevEngRegion*>& adapted_regions); + + /// Extract points with deviant accuracy. The removed points are divided into + /// connected groups. The current region must be associated a surface + void extractOutPoints(std::vector<std::pair<double, double> >& dist_ang, + double tol, double angtol, + std::vector<std::vector<RevEngPoint*> >& out_groups); + + /// Remove specified points from the current region. Information related to the + /// region in the points is unset + void removeAndUpdatePoints(vector<RevEngPoint*>& points); + + /// Identify points associated to a blend surface corresponding to an edge + /// between this region and another region. + void extractOutOfEdge(shared_ptr<CurveOnSurface>& cv, + std::vector<shared_ptr<CurveOnSurface> >& intcv, + double radius, double tol, double angtol, + std::vector<RevEngPoint*>& out_points); + + /// Identify points on the "other side" of an edge between this region and another + /// region. + void extractOutOfEdge2(std::vector<shared_ptr<CurveOnSurface> >& intcv, + double tol, double angtol, + std::vector<RevEngPoint*>& out_points); + + /// Identify points with deviant accuracy. The limit for being deviant is + /// set dependent on tol and avd + void identifyDistPoints(std::vector<std::pair<double, double> >& dist_ang, + double tol, double maxd, double avd, + std::vector<RevEngPoint*>& dist_points); + + /// Check if the region points are connected trough edges + bool isConnected(); + + /// Split into connected groups + /// \param move A sub set of the region points to check for connectivity. + /// \param out_groups Connected sub groups of move + /// \param outer Whether or not only sub groups of move at the boundary of this + /// regions is to be added to out_groups + /// \param inner The remaining points in move if outer = true + void connectedGroups(std::vector<RevEngPoint*>& move, + std::vector<std::vector<RevEngPoint*> >& out_groups, + bool outer, std::vector<RevEngPoint*>& inner); + + /// Extract specified points from the region. The specified points are + /// divided into connected groups. If outer=true, points from move internal to + /// the regions are kept + void extractSpesPoints(std::vector<RevEngPoint*>& move, + std::vector<std::vector<RevEngPoint*> >& out_groups, + bool outer=false); + + /// Extract points with deviant accuracy. The removed points are divided into + /// connected groups. The current region must be associated a surface + void extractOutPoints(int dir, double tol, double angtol, + double angtol2, + std::vector<std::vector<RevEngPoint*> >& out_groups); + + /// Remove specified points from the current region. Points are not updated + void removePoints(std::vector<RevEngPoint*>& remove); + + /// Enquire region classification. Unstable information + int getClassification() + { + if (classification_type_ == CLASSIFICATION_CURVATURE) + return group_points_[0]->C1_surf(); + else + return -1; + } + + /// Check if the regions is classified for being represented by a cylinder. Unstable information + bool cylindertype() + { + if (classification_type_ == CLASSIFICATION_CURVATURE) + return (group_points_[0]->C1_surf() == C1_RIDGE || + group_points_[0]->C1_surf() == C1_VALLEY); + else + return false; + } + + /// Check if the regions is classified for being represented by a plane. Unstable information + bool planartype() + { + if (classification_type_ == CLASSIFICATION_CURVATURE) + return (group_points_[0]->C1_surf() == C1_FLAT); + else + return false; + } + + /// Approximate region points with a plane if feasible, and register the plane + /// in the region. Possibly extract devinant points in connected groups + /// \param mainaxis Local coordinate system for model + /// \param tol Approximation tolerance + /// \param min_pt Not used + /// \param min_pt_reg Not used + /// \param angtol Angular tolerance + /// \param prefer_elementary Used in checking if an already existing surface should be replaced + /// \param hedgesfs New surface + /// \param prevsfs Possibly previous surface being replaced + /// \param out_groups Deviant points being removed from region + bool extractPlane(Point mainaxis[3], + double tol, int min_pt, int min_pt_reg, double angtol, + int prefer_elementary, + std::vector<shared_ptr<HedgeSurface> >& hedgesfs, + std::vector<HedgeSurface*>& prevsfs, + std::vector<std::vector<RevEngPoint*> >& out_groups); + + /// Approximate region points with a cylinder if feasible, and register the cylinder + /// in the region. Possibly extract devinant points in connected groups + /// \param tol Approximation tolerance + /// \param min_pt Minimum number of points left after extracting deviant points to create + /// a surface + /// \param min_pt_reg Not used + /// \param angtol Angular tolerance + /// \param prefer_elementary Used in checking if an already existing surface should be replaced + /// \param hedgesfs New surface + /// \param prevsfs Possibly previous surface being replaced + /// \param out_groups Deviant points being removed from region + /// \param repeat Indicates that points are removed and another try to fit a cylinder is recommended + bool extractCylinder(double tol, int min_pt, int min_pt_reg, + double angtol, int prefer_elementary, + std::vector<shared_ptr<HedgeSurface> >& hedgesfs, + std::vector<HedgeSurface*>& prevsfs, + std::vector<std::vector<RevEngPoint*> >& out_groups, + bool& repeat); + + /// Check if the regions is suitable for being represented by a plane. Unstable information + bool feasiblePlane(double zero_H, double zero_K) const; + + /// Check if the regions is suitable for being represented by a cylinder. Unstable information + bool feasibleCylinder(double zero_H, double zero_K) const; + + /// Approximate region points with a sphere if feasible, and register the sphere + /// in the region. Possibly extract devinant points in connected groups + /// \param mainaxis Local coordinate system for model + /// \param tol Approximation tolerance + /// \param min_pt Not used + /// \param min_pt_reg Not used + /// \param angtol Angular tolerance + /// \param prefer_elementary Used in checking if an already existing surface should be replaced + /// \param hedgesfs New surface + /// \param prevsfs Possibly previous surface being replaced + /// \param out_groups Deviant points being removed from region + bool extractSphere(Point mainaxis[3], + double tol, int min_pt, int min_pt_reg, + double angtol, int prefer_elementary, + std::vector<shared_ptr<HedgeSurface> >& hedgesfs, + std::vector<HedgeSurface*>& prevsfs, + std::vector<std::vector<RevEngPoint*> >& out_groups); + + /// Approximate region points with a linear swept spline surface if feasible, and register + /// the surface in the region. NB! Currently not in use + /// \param mainaxis Local coordinate system for model + /// \param tol Approximation tolerance + /// \param min_pt Not used + /// \param min_pt_reg Not used + /// \param angtol Angular tolerance + /// \param prefer_elementary Used in checking if an already existing surface should be replaced + /// \param hedgesfs New surface + /// \param prevsfs Possibly previous surface being replaced + bool extractLinearSweep(double tol, int min_pt, int min_pt_reg, + double angtol, int prefer_elementary, + std::vector<shared_ptr<HedgeSurface> >& hedgesfs, + std::vector<HedgeSurface*>& prevsfs); + + /// Approximate region points with a cone if feasible, and register the plane + /// in the region. Possibly extract devinant points in connected groups + /// \param tol Approximation tolerance + /// \param min_pt Not used + /// \param min_pt_reg Not used + /// \param angtol Angular tolerance + /// \param prefer_elementary Used in checking if an already existing surface should be replaced + /// \param hedgesfs New surface + /// \param prevsfs Possibly previous surface being replaced + /// \param out_groups Deviant points being removed from region + bool extractCone(double tol, int min_pt, int min_pt_reg, + double angtol, int prefer_elementary, + std::vector<shared_ptr<HedgeSurface> >& hedgesfs, + std::vector<HedgeSurface*>& prevsfs, + std::vector<std::vector<RevEngPoint*> >& out_groups); + + /// Approximate region points with a torus if feasible, and register the torus + /// in the region. Possibly extract devinant points in connected groups + /// \param mainaxis Local coordinate system for model + /// \param tol Approximation tolerance + /// \param min_pt Not used + /// \param min_pt_reg Not used + /// \param angtol Angular tolerance + /// \param prefer_elementary Used in checking if an already existing surface should be replaced + /// \param hedgesfs New surface + /// \param prevsfs Possibly previous surface being replaced + /// \param out_groups Deviant points being removed from region + bool extractTorus(Point mainaxis[3], + double tol, int min_pt, int min_pt_reg, + double angtol, int prefer_elementary, + std::vector<shared_ptr<HedgeSurface> >& hedgesfs, + std::vector<HedgeSurface*>& prevsfs, + std::vector<std::vector<RevEngPoint*> >& out_groups); + + /// Approximate region points with a torus using context information if feasible, and + /// register the torus in the region. Possibly extract devinant points in connected groups + /// \param mainaxis Local coordinate system for model + /// \param tol Approximation tolerance + /// \param min_pt Not used + /// \param min_pt_reg Minimum number of points left after extracting deviant points to create + /// a surface + /// \param angtol Angular tolerance + /// \param prefer_elementary Used in checking if an already existing surface should be replaced + /// \param hedgesfs New surface + /// \param prevsfs Possibly previous surface being replaced + /// \param out_groups Deviant points being removed from region + bool contextTorus(Point mainaxis[3], + double tol, int min_pt, int min_pt_reg, + double angtol, int prefer_elementary, + std::vector<shared_ptr<HedgeSurface> >& hedgesfs, + std::vector<HedgeSurface*>& prevsfs, + std::vector<std::vector<RevEngPoint*> >& out_groups); + + /// Approximate region points with a cylinder using context information if feasible, and + /// register the cylinder in the region. Possibly extract devinant points in connected groups + /// \param mainaxis Local coordinate system for model + /// \param tol Approximation tolerance + /// \param min_pt Not used + /// \param min_pt_reg Minimum number of points left after extracting deviant points to create + /// a surface + /// \param angtol Angular tolerance + /// \param prefer_elementary Used in checking if an already existing surface should be replaced + /// \param hedgesfs New surface + /// \param prevsfs Possibly previous surface being replaced + /// \param out_groups Deviant points being removed from region + bool contextCylinder(Point mainaxis[3], + double tol, int min_pt, int min_pt_reg, + double angtol, int prefer_elementary, + std::vector<shared_ptr<HedgeSurface> >& hedgesfs, + std::vector<HedgeSurface*>& prevsfs, + std::vector<std::vector<RevEngPoint*> >& out_groups); + + + /// Approximate region points with a sphere or a torus using context information from an + /// adjacent cylinder if feasible, and register the surface in the region. + /// Possibly extract devinant points in connected groups + /// \param mainaxis Local coordinate system for model + /// \param tol Approximation tolerance + /// \param min_pt Used to check if an approximation is accepted + /// \param min_pt_reg Not used + /// \param angtol Angular tolerance + /// \param prefer_elementary Used in checking if an already existing surface should be replaced + /// \param hedgesfs New surface + /// \param prevsfs Possibly previous surface being replaced + /// \param out_groups Deviant points being removed from region + bool adjacentToCylinder(Point mainaxis[3], + double tol, int min_pt, int min_pt_reg, + double angtol, int prefer_elementary, + std::vector<shared_ptr<HedgeSurface> >& hedgesfs, + std::vector<HedgeSurface*>& prevsfs, + std::vector<std::vector<RevEngPoint*> >& out_groups); + + /// Return closest region point to a given position along with the distance between + /// the points + RevEngPoint* closestPoint(const Point& pos, double& dist); + + /// Return all region points that has neighbours belonging to a different region + std::vector<RevEngPoint*> extractBdPoints(); + + /// Return all region points that has neighbours belonging to a specified region + std::vector<RevEngPoint*> extractBdPoints(std::vector<RevEngRegion*> regions); + + /// Return all region points that has neighbours belonging to more than one region + /// different from current + std::vector<RevEngPoint*> extractBranchPoints(); + + /// Identify adjacent regions with and without an associated surface that are + /// candidates for being included in the current region + void getAdjCandMerge(std::vector<RevEngRegion*>& adj_surf, + std::vector<RevEngRegion*>& adj_nosurf); + + /// Estimate the length and width of a potential blend surface adjacent to this + /// region along the curves in cvs + void estimateBlendDimensions(std::vector<shared_ptr<CurveOnSurface> >& cvs, + std::vector<RevEngPoint*>& bd_points, + double tol, double distlim, + std::vector<std::pair<double,double> >& t1_t2, + std::vector<double>& width, int& num_in_lim); + + /// Extract points lying within a specified distance to a given curve where + /// the projection onto the curve falls within parameter interval <tmin, tmax> + void getNearPoints(shared_ptr<CurveOnSurface>& cvs, + double& tmin, double& tmax, double width, double angtol, + std::vector<RevEngPoint*>& nearpoints); + + /// Extract points lying within a specified distance to a given set of curves + void getNearPoints2(std::vector<RevEngPoint*>& points, + shared_ptr<CurveOnSurface>& cv, + double width, std::vector<RevEngPoint*>& nearpoints); + + /// Extract those points in points that satisfies given conditions with + /// respect to the region surface + std::vector<RevEngPoint*> + removeOutOfSurf(std::vector<RevEngPoint*>& points, + double tol, double angtol, bool outer, double& min_dist); + + /// Grow current region, which has a surface that is realistically bounded by + /// constant parameter curves (blend surface) with points from the region adjacent + /// if they satisfy the accuracy constraints + void growInDomain(RevEngRegion *adjacent, double tol, double angtol); + + /// Check if a current surface can possibly be replaced by a surface with + /// better accuracy + bool tryOtherSurf(int prefer_elementary, bool replace); + + /// Approximate region points with a spline surface if feasible, and register + /// the surface in the region. NB! Currently not in use + /// \param tol Approximation tolerance + /// \param min_pt Used in checking if the surface is feasible + /// \param min_pt_reg Not used + /// \param angtol Angular tolerance + /// \param prefer_elementary Used in checking if an already existing surface should be replaced + /// \param hedgesfs New surface + /// \param prevsfs Possibly previous surface being replaced + bool extractFreeform(double tol, int min_pt, int min_pt_reg, + double angtol, int prefer_elementary, + std::vector<shared_ptr<HedgeSurface> >& hedgesfs, + std::vector<HedgeSurface*>& prevsfs, + std::vector<std::vector<RevEngPoint*> >& out_groups); + + /// Divide composite region into more consistent pieces by extracting a planar piece + /// and requiring the remaining parts to be connected + void segmentByPlaneGrow(Point mainaxis[3], double tol, + double angtol, int min_pt, + std::vector<shared_ptr<HedgeSurface> >& hedgesfs, + std::vector<HedgeSurface*>& prevsfs, + std::vector<std::vector<RevEngPoint*> >& out_groups); + + /// Divide composite region into more consistent pieces sorting points with respect from + /// surface normals of adjacent planar surfaces. Regions with planar points are grown from + /// this region. Cylindrical surfaces may be recognized. + /// and requiring the remaining parts to be connected + bool segmentByPlaneAxis(Point mainaxis[3], int min_point_in, + int min_pt_reg, + double tol, double angtol, int prefer_elementary, + std::vector<RevEngRegion*>& adj_planar, + std::vector<shared_ptr<HedgeSurface> >& hedgesfs, + std::vector<shared_ptr<RevEngRegion> >& added_reg, + std::vector<HedgeSurface*>& prevsfs, + std::vector<std::vector<RevEngPoint*> >& added_groups); + + /// Set pointer to associated surface. Remove possible previous surface + void setHedge(HedgeSurface* surface) + { + associated_sf_.clear(); + associated_sf_.push_back(surface); + computeDomain(); + } + + /// Add an additional associated surface. Obsolete! + void addHedge(HedgeSurface* surface) + { + associated_sf_.push_back(surface); + computeDomain(); + } + + /// Enquire if a region is associated a surface + bool hasSurface() + { + return (associated_sf_.size() > 0); + } + + /// Enquire the number of associated surfaces. Always one! + int numSurface() + { + return (int)associated_sf_.size(); + } + + /// Return specified surface + HedgeSurface* getSurface(int ix) + { + return (ix < 0 || ix>=(int)associated_sf_.size()) ? 0 : associated_sf_[ix]; + } + + /// Remove associated surface + void clearSurface() + { + if (associated_sf_.size() > 0) + associated_sf_.clear(); + maxdist_ = avdist_ = 0.0; + num_inside_ = num_inside2_ = 0; + } + + /// Compute accuracy and set associated surface + void setAssociatedSurface(shared_ptr<ParamSurface>& surf, + double tol, double angtol, int min_pt_reg, + shared_ptr<HedgeSurface>& hedge); + + /// Modify region point collection. Used when the radius of a blend cylinder or + /// torus is modified + /// \param points_out Points to extract + /// \param points_in Points to include + void updateWithPointsInOut(std::vector<RevEngPoint*>& points_out, + std::vector<RevEngPoint*>& points_in, + double tol, double angtol); + + /// Move points from points into blend_points if appropriate depending on + /// the distance to cvs and the flag in_blend + void sortBlendPoints(std::vector<RevEngPoint*>& points, + std::vector<shared_ptr<CurveOnSurface> >& cvs, + double distance, bool in_blend, + std::vector<RevEngPoint*>& blend_points); + + /// Move points from points into this region or other region if appropriate + /// Points with a distance to cvs larger than distance are moved + void sortBlendPoints(std::vector<RevEngPoint*>& points, + std::vector<shared_ptr<CurveOnSurface> >& cvs, + double distance, RevEngRegion* other, + std::vector<RevEngPoint*>& blend_points1, + std::vector<RevEngPoint*>& blend_points2); + + /// Enquire flag on surface accuracy + int getSurfaceFlag() + { + return surfflag_; + } + + /// Set flag on surface accuracy + void setSurfaceFlag(int surfflag) + { + surfflag_ = surfflag; + } + + /// Enquire information about the history of the associated surface. Information not + /// consistently carried out + int getAdaptionHistory() + { + return surf_adaption_; + } + + /// Return containing domain of the parameter values of the region points in the + /// parameter domain of the associated surface. + void getDomain(double dom[4]) + { + for (int ka=0; ka<4; ++ka) + dom[ka] = domain_[ka]; + } + + + /// Set containing domain of parameter points + void setDomain(double dom[4]) + { + for (int ka=0; ka<4; ++ka) + domain_[ka] = dom[ka]; + } + + /// Check if a fitted surface is accurate enough with respect to given tolerances, + /// number of region points and computed accuracy. Old function. Use defineSfFlag + bool accuracyOK(int min_pt, double tol, int num_inside, double avdist) + { + return (num_inside > min_pt && num_inside > (int)group_points_.size()/2 && + avdist <= tol); + } + + /// Check if a fitted surface is accurate enough with respect to given tolerances + /// and computed accuracy. Old function. Use defineSfFlag + bool accuracyOK(int num_points, int min_pt, double tol, int num_inside, + double avdist) + { + return (num_inside > min_pt && num_inside > num_points/2 && + avdist <= tol); + } + + /// Check if a fitted surface is accurate enough with respect to given tolerances, + /// number of region points and computed accuracy. + /// \param min_point Function returns not set if the number of OK points is less than min_point + /// \param tol Approximation tolerance + /// \param num_in Number of points that satisfy the distance and angular tolerances + /// \param num_in2 Number of points that satisfy the distance tolerance + /// \param avd Average absolute distance between the points and the surface + /// \param type_cyl True if the surface is a cylinder or a cone + int defineSfFlag(int min_point, double tol, int num_in, + int num_in2, double avd, bool type_cyl); + + /// Check if a fitted surface is accurate enough with respect to given tolerances, + /// given number of points and computed accuracy. + /// To be applied for a point group different from any region points + /// \param num_points Number of points tested for accuracy + /// \param min_point Function returns not set if the number of OK points is less than min_point + /// \param tol Approximation tolerance + /// \param num_in Number of points that satisfy the distance and angular tolerances + /// \param num_in2 Number of points that satisfy the distance tolerance + /// \param avd Average absolute distance between the points and the surface + /// \param type_cyl True if the surface is a cylinder or a cone + int defineSfFlag(int num_points, int min_point, double tol, int num_in, + int num_in2, double avd, bool type_cyl); + + /// Compute containing parameter domain of region points. Requires an associated surface + void computeDomain(); + + /// Bounding box for region points + const BoundingBox& boundingBox() + { + return bbox_; + } + + /// Enquire direction cone for LocFuncnormal_ (normal based on local approximating function) + /// in the region points + const DirectionCone& getNormalCone() + { + return normalcone_; + } + + /// Enquire direction cone for triangulation normal in the region points + const DirectionCone& getNormalConeTriang() + { + return normalcone2_; + } + + /// Enquire range of principal curvatures in the region points + void getPrincipalCurvatureInfo(double& mink1, double& maxk1, double& mink2, double& maxk2) + { + mink1 = mink1_; + maxk1 = maxk1_; + mink2 = mink2_; + maxk2 = maxk2_; + } + + /// Enquire average Gauss and mean curvatures in the region points + /// \param avH Average mean curvature + /// \param avK Average Gauss curvature + /// \param MAH Average absolue mean curvature + /// \param MAK Average absolute Gauss curvature + void getAvCurvatureInfo(double& avH, double& avK, double& MAH, double& MAK) + { + avH = avH_; + avK = avK_; + MAH = MAH_; + MAK = MAK_; + } + + /// Enquire average LocFuncnormal_ (normal based on local approximating function) + Point getMeanNormal() + { + return avnorm_; + } + + /// Enquire average triangle normal + Point getMeanNormalTriang() + { + return avnorm2_; + } + + /// Set accuracy information of region points + /// \param maxdist Maximum distance + /// \param avdist Average absolute distance + /// \param num_inside Number of points satisfying distance and angular tolerance, + /// \param num_inside2 Mumber of points satisfying distance tolerance + void setAccuracy(double maxdist, double avdist, int num_inside, + int num_inside2); + + /// Enquire accuracy information of region points + /// \param maxdist Maximum distance + /// \param avdist Average absolute distance + /// \param num_inside Number of points satisfying distance and angular tolerance, + /// \param num_inside2 Mumber of points satisfying distance tolerance + void getAccuracy(double& maxdist, double& avdist, int& num_inside, + int& num_inside2) + { + maxdist = maxdist_; + avdist = avdist_; + num_inside = num_inside_; + num_inside2 = num_inside2_; + } + + /// Enquire average absolute distance betweeb region points and surface + double getAverageDist() + { + return avdist_; + } + + /// Enquire number of points satisfying distance and angular tolerance + int getNumInside() + { + return num_inside_; + } + + /// Enquire number of points satisfying distance tolerance + int getNumInside2() + { + return num_inside2_; + } + + /// Enquire maximum distance between region points and surface + double getMaxSfDist() + { + return maxdist_; + } + + /// Return distance to surface and angle between surface and point normal for all points + void getDistAndAng(std::vector<std::pair<double,double> >& distang); + + /// In traversing points. Set as visited/not visited + void setVisited(bool visited) + { + visited_ = visited; + } + + /// In traversing points. Check if visited + bool visited() + { + return visited_; + } + + /// Check if the region is likely to correspond to a plane. Unstable information + bool possiblePlane(double angtol, double inlim); + + /// Check if the region is likely to correspond to a cylinder. Unstable information + bool possibleCylinder(double angtol, double inlim); + + /// Check if the region is likely to correspond to a cone. Unstable information + bool possibleCone(double angtol, double inlim); + + /// Check if the region is likely to correspond to a torus. Unstable information + bool possibleTorus(double angtol, double inlim); + + /// Check if the regions contains information for defining a swept surface + bool hasSweepInfo() + { + return (sweep_.get() != 0); + } + + /// Check if the regions contains information for defining a swept surface, and + /// whether it is linear or rotational (not implemented) sweep + int sweepType() + { + return (sweep_.get() ? sweep_->type_ : 0); + } + + /// Enquire if the regions contains information on how to split this composite + /// region into consistent pieces + bool hasDivideInfo() + { + return (seg_info_.size() > 0); + } + + /// Enquire number of information entities on how to split this composite + /// region into consistent pieces + int numDivideInfo() + { + return (int)seg_info_.size(); + } + + /// Define adjacency between this region and regions having points that are + /// neighbours to this regions points + void setRegionAdjacency(); + + /// Update information about neighbouring regions + void updateRegionAdjacency(); + + /// Include this region into an adjacent region if feasible + bool integrateInAdjacent(double mean_edge_len, int min_next, + int max_next, double tol, double angtol, + int max_nmb_outlier, RevEngRegion* taboo=0); + + /// Change parameterization of associated surface of type plane and update + /// parameter values of region points + void setPlaneParam(int min_pt_reg, Point mainaxis[3], double tol, double angtol); + + /// Given model coordinate system and axes from surfaces in adjacent region, + /// modify the surface in this region to adapt to the most feasible of the candidate + /// axes. Change surface if the accuracy of the new surface is sufficient + bool updateSurfaceWithAxis(int min_pt_reg, Point adj_axis, + Point mainaxis[3], int ix, double tol, + double angtol, Point pos); + + /// Add new adjacent region to the set of adjacent regions. NB! The adjacent region is not + /// updated with information about this region + void addAdjacentRegion(RevEngRegion* adj_reg) + { + //adj_reg->addAdjacentRegion(this); + adjacent_regions_.insert(adj_reg); + } + + /// Remove adjacent region from the set of adjacent regions. NB! The adjacent region is not + /// updated + void removeAdjacentRegion(RevEngRegion* adj_reg) + { + //adj_reg->removeAdjacentRegion(this); + if (std::find(adjacent_regions_.begin(), adjacent_regions_.end(), adj_reg) != adjacent_regions_.end()) + adjacent_regions_.erase(adj_reg); + // else + // std::cout <<"Something wrong in adjacent regions" << std::endl; + } + + /// Remove all information about region adjacency. NB! adjacent regions are not updated + void clearRegionAdjacency() + { + adjacent_regions_.clear(); + } + + /// Check if this region is adjacent to adj_reg + bool isAdjacent(RevEngRegion* adj_reg) + { + return (adjacent_regions_.find(adj_reg) != adjacent_regions_.end()); + } + + /// Check if this region is adjacent to a regions that is adjacent to adj_reg + bool isNextToAdjacent(RevEngRegion* adj_reg) + { + for (auto it=adjacent_regions_.begin(); it!=adjacent_regions_.end(); ++it) + { + bool adjacent = (*it)->isAdjacent(adj_reg); + if (adjacent) + return true; + } + return false; + } + + /// Fetch all regions adjacent to this region and adj_reg + std::vector<RevEngRegion*> commonAdjacent(RevEngRegion* adj_reg); + + /// Enquire number of adjacent regions + int numAdjacentRegions() + { + return (int)adjacent_regions_.size(); + } + + /// Fetch all adjacent regions + void getAdjacentRegions(std::vector<RevEngRegion*>& adjacent) + { + adjacent.insert(adjacent.end(), adjacent_regions_.begin(), adjacent_regions_.end()); + } + + /// Remove current regions from the adjacency information of all adjacent regions + void removeFromAdjacent() + { + for (auto it=adjacent_regions_.begin(); it!=adjacent_regions_.end(); ++it) + (*it)->removeAdjacentRegion(this); + } + + /// Collect adjacent regions with and associated planar surface + std::vector<RevEngRegion*> fetchAdjacentPlanar(); + + /// Collect adjacent regions with and associated cylindrical surface + std::vector<RevEngRegion*> fetchAdjacentCylindrical(); + + /// Divide composite region into simpler pieces using information from + /// adjacent regions + bool segmentByAdjSfContext(Point mainaxis[3], int min_point_in, + int min_pt_reg, double tol, double angtol, + std::vector<RevEngRegion*>& adj_planar, + std::vector<std::vector<RevEngPoint*> >& added_groups); + + /// Sort region points into groups with point normal being close to parallel or + /// close to orthogonal to a set of axes (axis) and a group of remaining points + bool sortByAxis(vector<Point>& axis, double tol, double axisang, double planeang, + std::vector<std::vector<RevEngPoint*> >& groups1, + std::vector<std::vector<RevEngPoint*> >& groups2, + std::vector<RevEngPoint*>& remaining); + + /// Identify cylindrical sub groups in a composite region and define cylindrical + /// surfaces. The remaining points are split into connected groups + bool extractCylByAxis(Point mainaxis[3], int min_point, int min_pt_reg, + double tol, double angtol, int prefer_elementary, + std::vector<shared_ptr<HedgeSurface> >& hedgesfs, + std::vector<shared_ptr<RevEngRegion> >& added_reg, + std::vector<std::vector<RevEngPoint*> >& out_groups, + std::vector<RevEngPoint*>& single_pts); + + /// Use segmentation information (SegmentData) to split composite region + bool divideWithSegInfo(int seg_ix, int min_pt_reg, + std::vector<std::vector<RevEngPoint*> >& sep_groups, + std::vector<RevEngPoint*>& single_pts); + + /// Return surfaces axis/surface normal from the adjacent region with surface and + /// most region points + Point directionFromAdjacent(double angtol); + + /// Divide composite region using direction from adjacent and split region points + /// according to the relation of their point normal to this direction + bool segmentByDirectionContext(int min_point_in, double tol, + const Point& direction, double angtol, + std::vector<std::vector<RevEngPoint*> >& added_groups); + + /// Check if context information (surfaces in adjacent regions) indicate that this + /// region could belong to a blend surface + bool potentialBlend(double angtol); + + /// Fetch adjacent regions to this region that has a blend relation to cvs + void neighbourBlends(std::vector<shared_ptr<CurveOnSurface> >& cvs, + double width, double tol, + std::vector<RevEngRegion*>& new_blends); + + /// Fetch adjacent regions with primary surfaces or primary base surfaces and surfaces + void getAdjacentElemInfo(std::vector<std::pair<shared_ptr<ElementarySurface>, RevEngRegion*> >& adj_elem, + std::vector<std::pair<shared_ptr<ElementarySurface>, RevEngRegion*> >& adj_elem_base); + + /// Flag the region with information about the region from which it was extracted + void setPreviousReg(RevEngRegion *prev) + { + prev_region_ = prev; + } + + /// Extend the pool of trimming curves in this region with curves identifying + /// boundaries between this region and adjacent regions with no surface or other + /// regions where no boundaries between this region and the other region is defined + void extendBoundaries(double mean_edge_len, int min_point_reg, double tol, + double angtol, Point mainaxis[3]); + + + /// Check if the region has a base surface defined. Partly displaced concept + bool hasBaseSf() + { + return basesf_.get(); + } + + /// Fetch base surface. Used in the context of defining a model coordinate system + shared_ptr<ParamSurface> getBase() + { + return basesf_; + } + + /// Fetch base surface including accuracy information. + void getBase(shared_ptr<ParamSurface>& base, double& maxd, double& avd, + int& num_in, int& num_in2) + { + base = basesf_; + maxd = maxdist_base_; + avd = avdist_base_; + num_in = num_in_base_; + num_in2 = num_in_base2_; + } + + /// Fetch accuracy information related to base surface. + void getBaseDist(double& maxd, double& avd, int& num_in, int& num_in2) + { + maxd = maxdist_base_; + avd = avdist_base_; + num_in = num_in_base_; + num_in2 = num_in_base2_; + } + + /// Update region with surface modified to adapt to a defined model axis + /// and set related parameterization and accuracy information + void updateSurfaceAndInfo(shared_ptr<ParamSurface> surf, + double tol, double angtol, + std::vector<double>& parvals, + std::vector<std::pair<double,double> >& dist_ang, + std::vector<RevEngEdge*>& nopar_edgs); + + /// Compute the approximation accuracy of this region with respect to a number of + /// primary surfaces. Select the best and return accuracy information + int checkSurfaceAccuracy(std::vector<shared_ptr<ElementarySurface> >& sfs, double tol, + double angtol, double& maxd, double& avd, int& num_in, + int& num2_in, int& sf_flag); + + /// Parameterize region points with respect to associated surface and update parameterization + /// and accuracy information in points and region + void parameterizePoints(double tol, double angtol); + + /// For each curve in cvs, fetch information on the part of the curve lying in the + /// vicinity of the region points + bool getCurveRestriction(std::vector<shared_ptr<CurveOnSurface> >& cvs, + double tol, double anglim, + std::vector<std::pair<double, double> >& endpars); + + /// Mark that this region should be associated to a future blend surface represented + /// by blend_edge + void setAssociatedBlend(RevEngEdge* blend_edge) + { + associated_blend_ = blend_edge; + } + + /// Check if this region is associated with a blend + bool hasAssociatedBlend() + { + return (associated_blend_ != 0); + } + + /// Fetch the edge representing the blend with which this region is associated + RevEngEdge* getAssociatedBlend() + { + return associated_blend_; + } + + /// Remove the edge representing a blend from this region + void removeAssociatedBlend() + { + associated_blend_ = 0; + } + + /// Check if this region is adjacent to any (future) blend surfaces + bool hasRevEdges() + { + return (rev_edges_.size() > 0); + } + + /// Check the number of (future) blend surfaces associated to this region + int numRevEdges() + { + return (int)rev_edges_.size(); + } + + /// Fetch a given edge representing a (future) blend surface + RevEngEdge* getRevEdge(int ix) + { + if (ix < 0 || ix >= (int)rev_edges_.size()) + return 0; + else + return rev_edges_[ix]; + } + + /// Fetch all edges representing (future) blend surfaces + std::vector<RevEngEdge*> getAllRevEdges() + { + return rev_edges_; + } + + /// Extend the collection of edges representing (future) blend surfaces + void addRevEdge(RevEngEdge* edge) + { + rev_edges_.push_back(edge); + } + + /// Remove edge from the collection of edges representing (future) blend surfaces + void removeRevEngEdge(RevEngEdge *edg) + { + auto it = std::find(rev_edges_.begin(), rev_edges_.end(), edg); + if (it != rev_edges_.end()) + rev_edges_.erase(it); + } + + /// Check if this region and the region other meets in a (future) blend surface + bool commonRevEdge(RevEngRegion *other); + + /// Check if this region and the region other are separated by a trimming curve + /// with twins + bool commonTrimEdge(RevEngRegion *other); + + /// Mark that is region corresponds to a blend surface and set pointer to the edge + /// representing this blend surface + void setBlendEdge(RevEngEdge* edge) + { + blend_edge_ = edge; + } + + /// Check if this region corresponds to a blend surface + bool hasBlendEdge() + { + return (blend_edge_ != 0); + } + + /// Fetch the edge containing information on e.g. the surfaces between which + /// the surface associated to this region is a blend + RevEngEdge* getBlendEdge() + { + return blend_edge_; + } + + /// Remove blend information from this region + void removeBlendEdge() + { + blend_edge_ = 0; + } + + /// Increase the collection of trimming curves in this region with edge + void addTrimEdge(shared_ptr<ftEdge> edge) + { + trim_edgs_.push_back(edge); + } + + /// Check if this region has any trimming information + bool hasTrimEdges() + { + return (trim_edgs_.size() > 0); + } + + /// Fetch the number of trimming curve associated to this region + int numTrimEdges() + { + return (int)trim_edgs_.size(); + } + + /// Fetch all trimming curves associated to this region + std::vector<shared_ptr<ftEdge> > getTrimEdges() + { + return trim_edgs_; + } + + /// Restrict the size of associated RevEngEdges with respect to the + /// extent of the region points + void adaptEdges(); + + /// Mark this region to be removed from the region pool in Reveng + void setRemove() + { + to_be_removed_ = true; + } + + /// Check if this region is to be removed from the region pool in Reveng + bool toBeRemoved() + { + return to_be_removed_; + } + + /// Trim associated surface with respect to the trimming curves of this region, + /// and replace the surface with a BoundedSurface if feasible + bool trimSurface(double tol); + + + /// Include the points of the region reg into this region, update parameterization + /// according to parvals and accuracy information according to maxd, avd, num_inside + /// num_inside2 and dist_ang, and update region adjacency information + void includeAdjacentRegion(RevEngRegion* reg, double maxd, double avd, + int num_inside, int num_inside2, + std::vector<double>& parvals, + std::vector<std::pair<double, double> >& dist_ang, + std::vector<RevEngRegion*>& added_adjacent); + + /// Check if the current region surface should be replaced by a blend surface + void checkEdgeAssociation(double tol, int min_point_reg, + std::vector<HedgeSurface*>& removed_sfs); + + /// Write debug information to file + void writeRegionInfo(std::ostream& of); + void writeRegionPoints(std::ostream& of); + void writeAdjacentPoints(std::ostream& of); + void writeUnitSphereInfo(std::ostream& of); + void writeSubTriangulation(std::ostream& of); + void writeSurface(std::ostream& of); + + /// Store current stage of region to file + void store(std::ostream& os) const; + + /// Read region information from file + void read(std::istream& is, shared_ptr<ftPointSet>& tri_sf, + std::vector<int>& associated_sf_id); + + private: + /// Unique id for region. Used in storing and reading data structure to and from file + int Id_; + + /// Triangle vertices with additional information collected into this region + /// Initially points belonging to classified segment. Updated during reverse engineering workflow + std::vector<RevEngPoint*> group_points_; + + /// Selected method for classification in work flow + int classification_type_; + int edge_class_type_; + + /// Surface associated to this region. Only one surface is stored + std::vector<HedgeSurface*> associated_sf_; + + /// Flag representing the accuracy with which the associated surface approximates the region + /// points + int surfflag_; + + /// History of surface approximation. Information not consistently carried out + int surf_adaption_; + + /// Rectangular domain surrounding the parameter pairs corresponding to the region points + /// and the associated surface + double domain_[4]; + + /// Range of principal curvatures for region points + double mink1_, maxk1_, mink2_, maxk2_; + + /// Average curvature in points: avH_ = mean, avK_ = Gauss, MAH_ = absolute valu of mean, + /// MAK_ = absolute value of Gauss + double avH_, avK_, MAH_, MAK_; + + /// Bounding box for region points + BoundingBox bbox_; + + /// Direction cone for LocFunc normal in region points + DirectionCone normalcone_; + + /// Direction cone for triangulation normal in region points + DirectionCone normalcone2_; + + /// Fraction of LocFunc normal in points being closes to the average LocFunc normal + /// than the given angular tolerance + double frac_norm_in_; + + /// Fraction of triangulation normal in points being closes to the average triangulation normal + /// than the given angular tolerance + double frac_norm_in2_; + + /// Average LocFunc normal + Point avnorm_; + + /// Average triangulation normal + Point avnorm2_; + + /// Maximum and average absolute value of distance between region points and surface + double maxdist_, avdist_; + + /// Number of points satisfying distance and angular tolerance and number of points + /// satisfyng the distance tolerance + int num_inside_, num_inside2_; + + /// Regions adjacent to this one + std::set<RevEngRegion*> adjacent_regions_; + + /// Set if the region is extracted from a previous region to avoid it being integrated + /// in the same region again + RevEngRegion* prev_region_; + + /// Alternative approximating surface with accuracy information + /// Can be set if the surface is modified due to adaption to model axes + shared_ptr<ParamSurface> basesf_; + double maxdist_base_, avdist_base_; + int num_in_base_, num_in_base2_; + + /// Associated edges representing (future) blend surfaces between this region surface + /// and another region surface + std::vector<RevEngEdge*> rev_edges_; + + /// The region points is associated blend surface represented by this edge + RevEngEdge* associated_blend_; + + /// The surface of this region is a blend surface associated to blend_edge + RevEngEdge* blend_edge_; + + /// Collection of trimming edges intended for eventually bounding the region surface + std::vector<shared_ptr<ftEdge> > trim_edgs_; + + /// Information that can be used to fit this regions points with a swept spline surface + shared_ptr<SweepData> sweep_; + + /// Indicates that this region is visited in a search + bool visited_; + + /// Indicates if this region is marked to be removed from the region pool in RevEng + bool to_be_removed_; + + /// Information suitable for dividing this region that is found to be composite into + /// simpler regions + std::vector<shared_ptr<SegmentData> > seg_info_;; + + struct grow_cand + { + RevEngRegion *cand_; + double maxd_, avd_, avang_; + int num_in_, num2_in_, ang_in_; + + grow_cand(RevEngRegion* cand, double maxd, double avd, double avang, + int num_in, int num2_in, int ang_in) + { + cand_ = cand; + maxd_ = maxd; + avd_ = avd; + avang_ = avang; + num_in_ = num_in; + num2_in_ = num2_in; + ang_in_ = ang_in; + } + }; + + void integrateGrowCand(std::vector<grow_cand>& cand, + Point mainaxis[3], double tol, + double angtol, std::vector<RevEngRegion*>& grown_regions, + std::vector<HedgeSurface*>& adj_surfs); + + void analyseNormals(double tol, Point& normal, Point& centre, double& radius); + void analysePlaneProperties(Point avnorm, double angtol, + std::vector<RevEngPoint*>& in, + std::vector<RevEngPoint*> out); + void analyseCylinderProperties(Point avvec, double angtol, + std::vector<RevEngPoint*>& in, + std::vector<RevEngPoint*> out); + void configSplit(std::vector<RevEngPoint*>& points, + std::vector<double>& param, + shared_ptr<Cylinder> cyl, + shared_ptr<SplineCurve> spl, double tol, + std::vector<std::vector<RevEngPoint*> >& configs); + shared_ptr<Plane> computePlane(std::vector<RevEngPoint*>& points, + const Point& norm_dir, Point mainaxis[3]); + shared_ptr<Cylinder> + computeCylinder(std::vector<RevEngPoint*>& points, double tol); + void analyseCylProject(shared_ptr<Cylinder> cyl, double tol, + std::vector<std::vector<RevEngPoint*> >& configs); + void analyseCylRotate(shared_ptr<Cylinder> cyl, double tol, + double avdist, int num_in, double& avdist_lin, + int& num_in_lin, double& avdist_cub, + int& num_in_cub, shared_ptr<Cone>& cone); + + shared_ptr<Sphere> computeSphere(Point mainaxis[3], Point adj_axis, + std::vector<RevEngPoint*>& points); + shared_ptr<Cone> computeCone(std::vector<RevEngPoint*>& points, Point& apex); + shared_ptr<Torus> computeTorus(std::vector<RevEngPoint*>& points, + std::vector<Point>& adj_axis, + double tol, double angtol); + shared_ptr<SplineSurface> computeLinearSwept(double tol, shared_ptr<SplineCurve>& profile, + Point& pt1, Point& pt2); + shared_ptr<SplineSurface> computeFreeform(std::vector<RevEngPoint*>& points, + double tol); + shared_ptr<SplineSurface> updateFreeform(std::vector<RevEngPoint*>& points, + double tol); + void getPCA(double lambda[3], Point& eigen1, Point& eigen2, Point& eigen3); + void getPCA(std::vector<RevEngPoint*>& points, + double lambda[3], Point& eigen1, Point& eigen2, Point& eigen3); + shared_ptr<SplineSurface> surfApprox(vector<RevEngPoint*>& points, + const BoundingBox& bbox); + void splitCylinderRad(const Point& pos, const Point& axis, + const Point& Cx, const Point& Cy, + int nmb_split, std::vector<Point>& centr, + std::vector<double>& rad); + void approximationAccuracy(std::vector<RevEngPoint*>& points, + shared_ptr<ParamSurface> surf, + double tol, double angtol, + double& maxd, double& avd, + std::vector<RevEngPoint*>& in, + std::vector<RevEngPoint*>& out); + bool parameterizeOnSurf(std::vector<RevEngPoint*>& points, + shared_ptr<ParamSurface> surf, + std::vector<double>& data, + std::vector<double>& param, + int& inner1, int& inner2, bool& close1, bool& close2); + bool parameterizeOnSurf(shared_ptr<ParamSurface> surf, + std::vector<double>& data, + std::vector<double>& param, + int& inner1, int& inner2, bool& close1, bool& close2); + bool reparameterize(std::vector<RevEngPoint*>& points, + std::vector<double>& param, std::vector<double>& param2, + double& umin, double& umax, double& vmin, double& vmax); + + bool reparameterize(std::vector<double>& param, std::vector<double>& param2, + double& umin, double& umax, double& vmin, double& vmax); + + void getParExtent(double curr[2], int pdir, std::vector<std::vector<int> >& raster, + int& i1, int& i2); + + void defineRaster(std::vector<double>& param, int nmb_div, + std::vector<std::vector<int> >& raster, double& umin, + double& umax, double& vmin, double& vmax); + + void extendInCorner(std::vector<double>& data, std::vector<double>& param, + double umin, double umax, double vmin, double vmax); + + bool computeIntegrateInfo(std::vector<RevEngPoint*>& points, RevEngRegion *adj_reg, + double tol, double angtol, double radius, bool local_approx, + int min_next, int max_next, int max_nmb_outlier, + bool& outlier, int& nmb_pt_adj, double& maxdist, + double& avdist, int& nmb_in, double& maxdist_adj, + double& avdist_adj, int& nmb_in_adj, + int& nmb_in_adj2); + + bool + analyseTorusContext(std::vector<std::pair<shared_ptr<ElementarySurface>, RevEngRegion*> >& adj, + double tol, double angtol, std::vector<size_t>& adjacent_ix, + int& plane_ix, int& cyl_ix, Point& pos, Point& axis, + Point& Cx, double& R1, double& R2, double cyl_dom[4], + bool& outer, bool& analyse_rotated); + bool + analyseCylinderContext(std::vector<std::pair<shared_ptr<ElementarySurface>, RevEngRegion*> >& adj, + double tol, double angtol, Point mainaxis[3], int mode, + std::vector<std::pair<shared_ptr<ElementarySurface>, RevEngRegion*> >& adj_planar, + Point& pos, Point& axis, Point& Cx, double& rad, + std::vector<RevEngPoint*>& cyl_pts); + + void computeFracNorm(double angtol, Point mainaxis[3], int nmb_axis[3], + double& in_frac1, double& in_frac2); + + shared_ptr<ElementarySurface> + helicalComponent(shared_ptr<Cylinder> cyl, double tol, + double angtol, int min_point, + int min_pt_reg, double avdist, int num_in2, + std::vector<std::pair<double,double> >& dist_ang, + std::vector<RevEngPoint*>& remaining, + std::vector<std::vector<RevEngPoint*> >& extracted, + double& maxd_out, double& avd_out, + int& num_in_out, int& num2_in_out, + std::vector<double>& parvals_out, + std::vector<std::pair<double,double> >& distang_out); + + bool defineHelicalInfo(shared_ptr<Cylinder> cyl, double tol, + double angtol, int min_point, int min_pt_reg, + double avdist, int num_in1, int num_in2, + std::vector<std::pair<double,double> >& dist_ang, + std::vector<shared_ptr<HedgeSurface> >& hedgesfs, + std::vector<std::vector<RevEngPoint*> >& out_groups, + std::vector<RevEngPoint*>& single_pts); + + bool defineConeFromCyl(shared_ptr<Cylinder> cyl, double tol, + double angtol, int min_pt_reg, + double avdist, int num_in, int num2_in, + std::vector<shared_ptr<HedgeSurface> >& hedgesfs, + std::vector<std::vector<RevEngPoint*> >& out_groups, + std::vector<RevEngPoint*>& single_pts); + + bool integratePlanarPoints(std::vector<Point>& dir, + std::vector<std::vector<RevEngPoint*> >& groups, + std::vector<std::pair<shared_ptr<ElementarySurface>,RevEngRegion*> >& adj_elem, + double tol, double angtol, + std::vector<RevEngPoint*>& remaining); + + bool defineCylindricalRegs(Point mainaxis[3], + std::vector<std::vector<RevEngPoint*> >& groups, + int min_point, int min_pt_reg, + double tol, double angtol, + std::vector<shared_ptr<RevEngRegion> >& added_reg, + std::vector<shared_ptr<HedgeSurface> >& hedgesfs, + std::vector<RevEngPoint*>& remaining); + + void axisFromAdjacent(double angtol, std::vector<Point>& axis); + + void identifyOutPoints(std::vector<std::pair<double,double> >& distang, + double tol, double angtol, double angtol2, + std::vector<vector<RevEngPoint*> >& out_groups, + std::vector<RevEngPoint*>& remaining); + + void getRemainingPoints(std::vector<RevEngPoint*>& curr_pts, + std::vector<RevEngPoint*>& remaining); + + void adaptOneEdge(shared_ptr<ftEdge>& edge, double dom[4]); + + bool arrangeEdgeLoop(double tol, std::vector<int>& adjusted); + + shared_ptr<CurveOnSurface> + constParSfCv(shared_ptr<ParamSurface> surf, int dir, + double par, int bd, double t1, double t2); + + void getDomainBoundaries(double tol, double angtol, + std::vector<std::pair<int, double> >& bd_par1, + std::vector<std::pair<int, double> >& bd_par2); + + void blendGrowFromAdjacent(RevEngRegion* adjacent, + std::vector<int>& pt_ix, double tol, + double angtol, + std::vector<RevEngPoint*>& grow_pt); + + // Select a point appropriate for starting the search for a sub group of points + // that can be approximated by a plane + RevEngPoint* seedPointPlane(int min_next, double rfac, double angtol); + + void updateRegion(double approx_tol, double anglim, + std::vector<RevEngRegion*>& adapted_regions, + std::vector<shared_ptr<RevEngRegion> >& outdiv_regions); + + void identifyAngPoints(std::vector<std::pair<double, double> >& dist_ang, + double tol, double disttol, + std::vector<RevEngPoint*>& ang_points); + + void identifyAngPoints(std::vector<std::pair<double, double> >& dist_ang, + double tol, double dtol, double dtol2, + std::vector<RevEngPoint*>& ang_points, + std::vector<RevEngPoint*>& remaining); + + void removeOtherPoints(std::vector<RevEngPoint*>& keep, + std::vector<HedgeSurface*>& prevsfs, + std::vector<std::vector<RevEngPoint*> >& out_groups); + + bool contextCylinder(Point mainaxis[3], + double tol, int min_pt, int min_pt_reg, + double angtol, int prefer_elementary, + std::vector<std::pair<shared_ptr<ElementarySurface>, RevEngRegion*> >& adj_elem, + std::vector<shared_ptr<HedgeSurface> >& hedgesfs, + std::vector<HedgeSurface*>& prevsfs, + std::vector<std::vector<RevEngPoint*> >& out_groups, + int mode=1); + + RevEngPoint* closestParPoint(const Point& parpt, double& dist); + + std::vector<RevEngPoint*> extractNextToAdjacent(RevEngRegion* reg); + + void extractPointsAtSeam(std::vector<RevEngPoint*>& seam_pts1, + std::vector<RevEngPoint*>& seam_pts2, bool along_udir); + + void testBlendGap(std::vector<shared_ptr<CurveOnSurface> >& cvs, + double tmin, double tmax, double tdel, double width, + std::vector<std::pair<double,double> >& not_gap); + + void growFromNeighbour(Point mainaxis[3], int min_pt_reg, + std::vector<RevEngPoint*>& seed, double tol, + double angtol, RevEngRegion *neighbour, + bool do_update=true); + + shared_ptr<ParamSurface> surfaceWithAxis(std::vector<RevEngPoint*>& points, + Point axis, Point pos, + Point mainaxis[3]); + + bool adjustWithCylinder(Point mainaxis[3], + double tol, double angtol, int min_pt_reg, + std::vector<std::vector<RevEngPoint*> >& out_groups, + std::vector<RevEngRegion*>& grown_regions, + std::vector<HedgeSurface*>& adj_surfs); + + void getAdjInsideDist(shared_ptr<ParamSurface> surf, double dom[4], + double tol, RevEngRegion* reg, + double& avd, double& ava, int& nn, + std::vector<RevEngPoint*>& adjpts, + std::vector<double>& par_and_dist); + + bool identifySignificantAxis(std::vector<std::pair<shared_ptr<ElementarySurface>, RevEngRegion*> >& adj, + Point& pos, Point& axis, Point& axis2); + + void analyseRotated(Point& pos, Point& axis, Point& axis2); + + shared_ptr<Torus> + analyseRotatedTorus(Point& pos, Point& Cx, Point& normal, + double tol, double angtol); + + bool isInBlend(std::vector<shared_ptr<CurveOnSurface> >& cvs, + double width, double tol, int& in_blend); + + std::vector<RevEngPoint*> sortPtsSeq(double mean_edge_len, + std::vector<RevEngPoint*>& seq_pts, + std::vector<RevEngPoint*>& sub_pts); + + vector<RevEngPoint*> extractBdOutPoints(shared_ptr<SplineCurve>& crv, + std::vector<RevEngPoint*>& seq_pts, + double tol); + + void adjustWithSurf(Point mainaxis[3], int min_pt_reg, double tol, double angtol); + + double getFracNormTriang() + { + return frac_norm_in2_; + } + + void setBaseSf(shared_ptr<ParamSurface> base, double maxd, double avd, + int num_in, int num_in2) + { + basesf_ = base; + maxdist_base_ = maxd; + avdist_base_ = avd; + num_in_base_ = num_in; + num_in_base2_ = num_in2; + } + + // Check if this region and the region adj both is connected to a triangulation + // vertex (not in any region) that is defined as an edge point + bool hasEdgeBetween(RevEngRegion* adj); + + void checkReplaceSurf(Point mainaxis[3], int min_pt_reg, double tol, + double angtol, bool always=false); + + void computeSurface(std::vector<RevEngPoint*>& points, + Point mainaxis[3], double tol, double angtol, + ClassType classtype, shared_ptr<ParamSurface>& updated, + shared_ptr<ParamSurface>& updated2, bool& cyllike); + + void curveApprox(std::vector<Point>& points, double tol, + shared_ptr<Circle> circle, + std::vector<double>& param, + shared_ptr<SplineCurve>& curve, Point& xpos); + + void getAdjacentBlends(std::vector<RevEngRegion*>& adj_blends); + + void rangeAlongAxis(const Point& pos, const Point& axis, double& tmin, + double& tmax); + + shared_ptr<Plane> + planarComponent(Point vec, int min_point, int min_pt_reg, + double tol, double angtol, Point mainaxis[3], + std::vector<RevEngPoint*>& remaining, + std::vector<std::vector<RevEngPoint*> >& extracted); + + bool planarComponent(Point vec, int min_point, int min_pt_reg, double tol, + double angtol, Point mainaxis[3], + std::vector<shared_ptr<HedgeSurface> >& hedgesfs, + std::vector<vector<RevEngPoint*> >& out_groups, + std::vector<RevEngPoint*>& single_pts, + bool create_surface = true); + +}; +} + +#endif diff --git a/compositemodel/include/GoTools/compositemodel/RevEngUtils.h b/compositemodel/include/GoTools/compositemodel/RevEngUtils.h new file mode 100644 index 00000000..5dcd1a66 --- /dev/null +++ b/compositemodel/include/GoTools/compositemodel/RevEngUtils.h @@ -0,0 +1,440 @@ +/* + * Copyright (C) 1998, 2000-2007, 2010, 2011, 2012, 2013 SINTEF ICT, + * Applied Mathematics, Norway. + * + * Contact information: E-mail: tor.dokken@sintef.no + * SINTEF ICT, Department of Applied Mathematics, + * P.O. Box 124 Blindern, + * 0314 Oslo, Norway. + * + * This file is part of GoTools. + * + * GoTools is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * GoTools 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with GoTools. If not, see + * <http://www.gnu.org/licenses/>. + * + * In accordance with Section 7(b) of the GNU Affero General Public + * License, a covered work must retain the producer line in every data + * file that is created or manipulated using GoTools. + * + * Other Usage + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial activities involving the GoTools library without + * disclosing the source code of your own applications. + * + * This file may be used in accordance with the terms contained in a + * written agreement between you and SINTEF ICT. + */ + +#ifndef _REVENGUTILS_H +#define _REVENGUTILS_H + +#include "GoTools/utils/Point.h" +#include "GoTools/compositemodel/RevEngPoint.h" +#include "GoTools/geometry/ParamSurface.h" +#include "GoTools/geometry/SplineSurface.h" +#include "GoTools/geometry/SplineCurve.h" +#include "GoTools/utils/BoundingBox.h" +#include <vector> + +namespace Go { + + class RevEngPoint; + class Line; + class Plane; + class Cylinder; + class Torus; + class Sphere; + class Cone; + + /** RevEngUtils - Utility functionality for everse engineering. + * + */ + + namespace RevEngUtils + { + /// Principal analysis based on a group of points + void principalAnalysis(Point& curr, std::vector<Point>& points, + double lambda[3], double eigenvec[3][3]); + + void principalAnalysis(std::vector<RevEngPoint*>& points, + double lambda[3], double eigenvec[3][3]); + + /// Rotate point group according to specified coordinate system (x=vec1, y=vec2), + /// and approximate points with a bicubic function. Compute surface normal and + /// principal curvatures + void computeLocFunc(Point& curr, std::vector<Point>& points, + Point& vec1, Point& vec2, Point& normal, Point& mincvec, + double& minc, Point& maxcvec, double& maxc, + double& currdist, double& avdist); + + /// Interface to the class SmoothSurf + void smoothSurf(shared_ptr<SplineSurface>& surf, int fixed); + + /// Approximate parameterized data points given information of polynomial degrees + /// and initial number of coefficients. Iterate until the tolerance tol or the + /// maximum number of iterations (max_iter) is reached. Parameter iteration is performed. + /// Output of accuracy (maximum distance, average distance and number of points outside + /// the tolerance) and final parameter pairs associated to the points + shared_ptr<SplineSurface> surfApprox(std::vector<double>& data, int dim, + std::vector<double>& param, int order1, + int order2, int nmb_coef1, int nmb_coef2, + bool close1, bool close2, + int max_iter, double tol, double& maxd, + double& avd, int& num_out, + std::vector<double>& parvals, + double del=0.0); + + /// Surface approximation given parameterized data points and information to create + /// spline space. Limits of parameter intervals is given by the parameterized points + shared_ptr<SplineSurface> surfApprox(std::vector<double>& data, int dim, + std::vector<double>& param, int order1, + int order2, int nmb_coef1, int nmb_coef2, + double del=0.0); + + /// Surface approximation given parameterized data points and information to create + /// spline space. Limits of parameter intervals is given as input + shared_ptr<SplineSurface> surfApprox(std::vector<double>& data, int dim, + std::vector<double>& param, int order1, + int order2, int nmb_coef1, int nmb_coef2, + double umin, double umax, double vmin, + double vmax); + + /// Paramerize RevEngPoints by projecting them onto a given plane (spanned by vec1 and + /// vec2). Extracted xyz values in data and parameters (uv) in param + void parameterizeWithPlane(std::vector<RevEngPoint*>& pnts, const BoundingBox& bbox, + const Point& vec1, const Point& vec2, + std::vector<double>& data, std::vector<double>& param); + + /// Paramerize points by projecting them onto a given plane (spanned by vec1 and + /// vec2). xyz values in data and parameters (uv) in param + void parameterizeWithPlane(std::vector<Point>& pnts, const BoundingBox& bbox, + const Point& vec1, const Point& vec2, + std::vector<double>& data, std::vector<double>& param); + + /// Parameterize RevEngPoints on the surface surf. Returns information to specify + /// a spline space in which the points can be approximated (inner1, inner2, close1, close2) + bool parameterizeOnPrimary(std::vector<RevEngPoint*>& points, + shared_ptr<ParamSurface> surf, + std::vector<double>& data, + std::vector<double>& param, + int& inner1, int& inner2, bool& close1, bool& close2); + + /// Cylinder axis and x- and y-vectors from a point group + void computeAxis(std::vector<Point>& points, + Point& axis, Point& Cx, Point& Cy); + + /// Cylinder axis and x- and y-vectors from a number of RevEngPoint groups + void computeAxis(std::vector<std::pair<std::vector<RevEngPoint*>::iterator, + std::vector<RevEngPoint*>::iterator> >& points, + Point& axis, Point& Cx, Point& Cy); + + /// Sphere centre and radius from a number of RevEngPoint groups + void + computeSphereProp(std::vector<std::pair<std::vector<RevEngPoint*>::iterator, + std::vector<RevEngPoint*>::iterator> >& points, + Point& centre, double& radius); + + /// Cone axis and x- and y-vectors from a number of RevEngPoint groups. If the + /// point group corresponds to a small cone sector, the function for computing + /// a cylinder axis may be more appropriate + void coneAxis(std::vector<std::pair<std::vector<RevEngPoint*>::iterator, + std::vector<RevEngPoint*>::iterator> >& points, + Point& axis, Point& Cx, Point& Cy); + + /// Compute cone apex and opening angle + void coneApex(std::vector<std::pair<std::vector<RevEngPoint*>::iterator, + std::vector<RevEngPoint*>::iterator> >& points, + Point axis, Point& apex, double& phi); + + /// Compute cylinder position and radius given point and axis + void computeCylPosRadius(std::vector<std::pair<std::vector<RevEngPoint*>::iterator, + std::vector<RevEngPoint*>::iterator> >& points, + Point& low, Point& high, Point& axis, Point& Cx, + Point& Cy, Point& pos, double& radius); + + /// Given 3D points in a plane given with normal and x- and y-axis, compute + /// circle center and radius + void computeCircPosRadius(std::vector<Point>& points, + const Point& axis, const Point& Cx, const Point& Cy, + Point& pos, double& radius); + + /// As above, given 3D points in a plane given with normal and x- and y-axis, compute + /// radius + void computeRadius(std::vector<Point>& points, + Point& axis, Point& Cx, Point& Cy, double& radius); + + /// Compute line approximating an unordered group of points + void computeLine(vector<Point>& points, Point& pos, Point& dir); + + /// Approximate a group of points with a plane using implicit approximation. + /// An initial surface normal guess must be provided. Returns point in plane and + /// surface normal + void computePlane(std::vector<Point>& points, Point normal, Point mainaxis[3], + Point& pos, Point& norm, Point& Cx, Point& Cy); + + /// Rotate a number of RevEngPoint groups around the axis axis with point mid and + /// return the resulting points in the plane spanned by xvec and axis + void rotateToPlane(std::vector<std::pair<std::vector<RevEngPoint*>::iterator, + std::vector<RevEngPoint*>::iterator> >& points, + Point& xvec, Point& axis, Point& mid, std::vector<Point>& rotated); + + /// Project a number of RevEngPoint groups into the plane represented by the point mid and the + /// normal axis and return the resulting points along with information about the distance + /// between the initial points and the plane + void projectToPlane(std::vector<std::pair<std::vector<RevEngPoint*>::iterator, + std::vector<RevEngPoint*>::iterator> >& points, + Point& axis, Point& mid, std::vector<Point>& projected, + double& maxdist, double& avdist, double dlen=-1.0); + + /// Project a number of RevEngPoints into the plane represented by the point mid and the + /// normal axis and return the resulting points along with information about the distance + /// between the initial points and the plane + void projectToPlane(std::vector<RevEngPoint*>& points, + Point& axis, Point& mid, std::vector<Point>& projected, + double& maxdist, double& avdist, double dlen=-1.0); + + /// Rotate points around the axis axis width point mid and return the resulting + /// points in the plane spanned by xvec and axis + void rotateToPlane(std::vector<Point>& points, + Point& xvec, Point& axis, Point& mid, std::vector<Point>& rotated); + + /// Compute distance between RevEngPoints and a surface, and summarize results + /// \param start Start iterator to vector of points + /// \param end Iterator to end of vector + /// \param surf Surface with whom the points will be compared + /// \param tol Approximation tolerance + /// \param maxdist Maximum distance between the point cloud and the surface + /// \param avdist Average absolute distance between the point cloud and the surface + /// \param inside Number of points where the distance is less than tol and the angle + /// between the surface normal and the normal in the point (least of triangle normal and + /// local function normal) is less than angtol if given + /// \param inside2 Number of points where the distance is less than tol + /// \param in Points being inside + /// \param out Points not being inside + /// \param parvals Parameter values of points projected onto the surface (u1, v1, u2, v2, ...) + /// \param distang Distance and angle difference between normal vectors for each point + void distToSurf(std::vector<RevEngPoint*>::iterator start, + std::vector<RevEngPoint*>::iterator end, + shared_ptr<ParamSurface> surf, double tol, + double& maxdist, double& avdist, + int& inside, int& inside2, + std::vector<RevEngPoint*>& in, + std::vector<RevEngPoint*>& out, + std::vector<double>& parvals, + std::vector<std::pair<double,double> >& distang, + double angtol=-1.0); + + /// As above. Slightly simplified interface + void distToSurf(std::vector<RevEngPoint*>::iterator start, + std::vector<RevEngPoint*>::iterator end, + shared_ptr<ParamSurface> surf, double tol, + double& maxdist, double& avdist, + int& inside, int& inside2, + std::vector<double>& parvals, + std::vector<std::pair<double,double> >& distang, + double angtol=-1.0); + + /// As above. Simplified interface + void distToSurf(std::vector<RevEngPoint*>& points, + shared_ptr<ParamSurface> surf, double tol, + double angtol, double& maxdist, double& avdist, + int& inside, int& inside2, + std::vector<std::pair<double,double> >& dist_ang); + + /// As above. Taking points as input. Simplified interface. Only distance + /// between points and surface is considered (normals not available) + void distToSurf(std::vector<Point>& points, + shared_ptr<ParamSurface> surf, double tol, + double& maxdist, double& avdist, int& inside, + std::vector<double>& distance); + + /// Distance between points and curve. + /// \param points Input points + /// \param curve Check distance to the curve + /// \param tol Approximation tolerance + /// \param maxdist Maximum distance between the point cloud and the curve + /// \param avdist Average absolute distance between the point cloud and the curve + /// \param inside Number of points where the distance is less than tol + /// \param parvals Parameter values of points projected onto the curve (t1, t2, ...) + /// \param dist Distance for each point + void distToCurve(std::vector<Point>& points, + shared_ptr<ParamCurve> curve, double tol, + double& maxdist, double& avdist, int& inside, + std::vector<double>& parvals, std::vector<double>& dist); + + /// Distance between points and curve. Slightly simplified intervace + void distToCurve(std::vector<Point>& points, + shared_ptr<ParamCurve> curve, double tol, + double& maxdist, double& avdist, int& inside, + std::vector<double>& dist); + + + /// Distance between points and curve. Simplified intervace + void distToCurve(std::vector<Point>& points, + shared_ptr<ParamCurve> curve, double tol, + double& maxdist, double& avdist, int& inside); + + /// Modify given primary surface (sf_in) to fit in the coordinate system given + /// by mainaxis + /// \param points Point group associated with the surface + /// \diag Used to bound the surface + shared_ptr<ElementarySurface> elemsurfWithAxis(shared_ptr<ElementarySurface> sf_in, + std::vector<RevEngPoint*>& points, + Point mainaxis[3], double diag); + + /// Compute plane with surface normal axis to best fit the point group points + /// \param init_loc Initial point in plane + /// \param mainaxis Used to define the plane parameterization + shared_ptr<Plane> planeWithAxis(std::vector<RevEngPoint*>& points, + Point axis, Point init_loc, + Point mainaxis[3]); + + /// Compute cylinder approximating the RevEngPoints points. The cylinder axis + /// axis is input. mainaxis is used to compute x- and y-vectors. The points low and high + /// are used to assist locating the cylinder point + shared_ptr<Cylinder> cylinderWithAxis(std::vector<RevEngPoint*>& points, + Point axis, Point low, + Point high, Point mainaxis[3]); + + /// Compute cylinder approximating the RevEngPoints points. The cylinder axis, + /// x-vector and point is given as input. The cylinder radius is computed + shared_ptr<Cylinder> cylinderWithAxis(std::vector<RevEngPoint*>& points, + Point axis, Point Cx, Point pos); + + /// Compute torus approximating the RevEngPoints points. The torus axis, + /// and mid point is given as input. Minor and major radius is computed. mainaxix + /// is used to define x- and y-vector + shared_ptr<Torus> torusWithAxis(std::vector<RevEngPoint*>& points, + Point axis, Point loc, + Point mainaxis[3]); + + /// Compute torus approximating the RevEngPoints points. The torus axis, + /// x-vector and mid point is given as input. Minor and major radius is computed. + shared_ptr<Torus> torusWithAxis(std::vector<RevEngPoint*>& points, + Point axis, Point Cx, Point pos); + + /// Approximate sphere from points. The sphere axis is given as input and the remaining + /// coordinate axes are computed from mainaxis + shared_ptr<Sphere> sphereWithAxis(std::vector<RevEngPoint*>& points, + Point axis, + Point mainaxis[3]); + + /// Compute sphere radius from points. Center and coordinate axes are given + shared_ptr<Sphere> sphereWithAxis(std::vector<RevEngPoint*>& points, + Point axis, Point Cx, Point pos); + + /// Compute cone approximating the RevEngPoints points. The cone axis + /// axis is input. mainaxis is used to compute x- and y-vectors. The points low and high + /// are used to assist locating a point on the axis + shared_ptr<Cone> coneWithAxis(vector<RevEngPoint*>& points, + Point axis, Point low, + Point high, Point mainaxis[3]); + + /// Compute cone approximating the RevEngPoints points. The axis, + /// x-vector and point on axis is given as input. The cone radius at the point and + /// the cone opening angle is computed + shared_ptr<Cone> coneWithAxis(std::vector<RevEngPoint*>& points, + Point axis, Point Cx, Point pos, + double len); + + /// Compute plane approximating a number of RevEngPoint groups (points) + /// \param bbox BoundingBox containing all points + /// \param nmbpts Number of points for each point group + /// \param set_bound Whether the plane should be bounded (from bbox information) + shared_ptr<ParamSurface> doMergePlanes(std::vector<std::pair<std::vector<RevEngPoint*>::iterator, + std::vector<RevEngPoint*>::iterator> > points, + const BoundingBox& bbox, + std::vector<int>& nmbpts, + bool set_bound = true); + /// Compute cylinder approximating a number of RevEngPoint groups (points) + /// Parameters as for doMergePlanes + shared_ptr<ParamSurface> doMergeCylinders(std::vector<std::pair<std::vector<RevEngPoint*>::iterator, + std::vector<RevEngPoint*>::iterator> > points, + const BoundingBox& bbox, + std::vector<int>& nmbpts, + bool set_bound = true); + /// Compute sphere approximating a number of RevEngPoint groups (points) + /// Parameters as for doMergePlanes + /// \param normal Axis through sphere poles. The sphere is initially bounded + shared_ptr<ParamSurface> doMergeSpheres(std::vector<std::pair<std::vector<RevEngPoint*>::iterator, + std::vector<RevEngPoint*>::iterator> > points, + const BoundingBox& bbox, + std::vector<int>& nmbpts, Point& normal); + + /// Compute torus approximating a number of RevEngPoint groups (points) + /// Parameters as for doMergePlanes. The torus is initially bounded + shared_ptr<ParamSurface> doMergeTorus(std::vector<std::pair<std::vector<RevEngPoint*>::iterator, + std::vector<RevEngPoint*>::iterator> > points, + const BoundingBox& bbox, + std::vector<int>& nmbpts); + + /// Middle curve between two spline curves + shared_ptr<SplineCurve> midCurve(shared_ptr<SplineCurve>& cv1, + shared_ptr<SplineCurve>& cv2); + + /// Approximate points with spline curve. The points are parameterized on the curve + /// cvin. ik=degree+1, in=number of coefficients + void curveApprox(std::vector<Point>& points, + shared_ptr<ParamCurve> cvin, + int ik, int in, + shared_ptr<SplineCurve>& curve); + + /// Approximate parameterized points with spline curve. ik=degree+1, in=number of coefficients + void curveApprox(std::vector<Point>& points, + std::vector<double>& param, + int ik, int in, + shared_ptr<SplineCurve>& curve); + + /// Approximate an ordered sequence of RevEngPoints by a spline curve with degree degree + /// Refinement of the intial spline space and reparameterization is performed at most maxiter + /// times + /// \param tol Approximation tolerance + shared_ptr<SplineCurve> createCurve(std::vector<RevEngPoint*>& points, int degree, + double tol, int maxiter); + + /// Extract points at the start or end of a point sequence where corresponding + /// points rotated into a given plane (input) can be approximated by a line. + /// Special function accessed from RevEngRegion + void extractLinearPoints(std::vector<RevEngPoint*>& points, + std::vector<Point>& rotated, double len, + Point& pos, Point& axis, double rad, + Point& axis2, bool plane, + double tol, double angtol, + std::vector<std::pair<double,double> >& dist_ang, + std::vector<RevEngPoint*>& linear, bool start, + std::vector<RevEngPoint*>& remaining); + + bool extractLinearPoints(std::vector<Point>& points, + shared_ptr<Line>& line, Point norm, double tol, + bool start, double& splitpar, + std::vector<Point>& linear, + std::vector<Point>& remaining); + + void identifyEndPoints(std::vector<RevEngPoint*> edge_pts, shared_ptr<CurveOnSurface>& sfcv, + RevEngPoint*& first_pt, double& t1, RevEngPoint*& last_pt, double& t2); + + /// Reorder curves to form a sequence. The parameter direction of curves may be changed + void setLoopSeq(std::vector<shared_ptr<CurveOnSurface> >& cvs); + + /// Identifyed groups of connected RevEngPoints (by triangle edges) in a given point group + void identifyConGroups(std::vector<RevEngPoint*>& init, + std::vector<std::vector<RevEngPoint*> >& groups); + } + +} // namespace Go + + +#endif // _REVENGUTILS_H + diff --git a/compositemodel/include/GoTools/compositemodel/compositemodel-doxymain.h b/compositemodel/include/GoTools/compositemodel/compositemodel-doxymain.h index e0b5df19..d1365cf1 100644 --- a/compositemodel/include/GoTools/compositemodel/compositemodel-doxymain.h +++ b/compositemodel/include/GoTools/compositemodel/compositemodel-doxymain.h @@ -237,5 +237,9 @@ size of the model. An upper bound of the tesselation size exists, but a large model combined with a small density will still lead to a heavy visualization model. +\section comp_sec3 Reverse engineering +The aim is to go from a triangulated point cloud to a boundary represented +CAD model. See \link reverseengineering_doc the reverse engineering page\endlink +for more information. */ #endif // _COMPOSITEMODEL_DOXYMAIN_H diff --git a/compositemodel/include/GoTools/compositemodel/reverseengineering_doxymain.h b/compositemodel/include/GoTools/compositemodel/reverseengineering_doxymain.h new file mode 100644 index 00000000..f79432d0 --- /dev/null +++ b/compositemodel/include/GoTools/compositemodel/reverseengineering_doxymain.h @@ -0,0 +1,384 @@ +/* + * Copyright (C) 1998, 2000-2007, 2010, 2011, 2012, 2013 SINTEF ICT, + * Applied Mathematics, Norway. + * + * Contact information: E-mail: tor.dokken@sintef.no + * SINTEF ICT, Department of Applied Mathematics, + * P.O. Box 124 Blindern, + * 0314 Oslo, Norway. + * + * This file is part of GoTools. + * + * GoTools is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * GoTools 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with GoTools. If not, see + * <http://www.gnu.org/licenses/>. + * + * In accordance with Section 7(b) of the GNU Affero General Public + * License, a covered work must retain the producer line in every data + * file that is created or manipulated using GoTools. + * + * Other Usage + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial activities involving the GoTools library without + * disclosing the source code of your own applications. + * + * This file may be used in accordance with the terms contained in a + * written agreement between you and SINTEF ICT. + */ + +#ifndef _REVERSEENGINEERING_DOXYMAIN_H +#define _REVERSEENGINEERING_DOXYMAIN_H + +/** +\page reverseengineering_doc Reverse engineering, from triangulated point cloud to CAD model. + +The defined workflow constitues an early prototype for reverse engineering. The +functionality is expected to be applied to mechanical objects. The mathematical +description of these types of objects is characterized by predominantly use of +primary surfaces, e.g. planes, cylinders, cones, spheres and torii. Free form +surfaces are used mostly for blends and small details. The extent of sharp edges in +the objects is small. Edges are in general blended. Relevant objects are often +made of casted iron or created by adaptive manufacturing giving rough surfaces. +Only the part of the surface that are critical for assembly is plastered, leaving +most of the part with small irregularities. Simple models and the main surfaces +of more complex models is expected to be reconstructed. + +\section re_sec1 Interface +The reverse engineering engine is the class +\link Go::RevEng RevEng\endlink. The class is instanciated with a triangulated surface +represented as an \link Go::ftPointSet ftPointSet\endlink, which represents a triangulation +in GoTools. Assume that the triangulation +is represented as a collection of vertices and triangles in the format +\verbatim + vector<double> vertices; + vector<int> triangles; +\endverbatim +The points are stored consequetive in vertices as (x,y,z) while three indices in triangles +represents one triangle. The triangles are expected to have a consistent orientation. The +vertices and triangles are transferred to ftPointSet with the following code snippet: +\verbatim + size_t nvertices = vertices.size()/3; + size_t ntriangles = triangles.size()/3; + shared_ptr<ftPointSet> tri_sf = shared_ptr<ftPointSet>(new ftPointSet()); + for (size_t ki=0; ki<nvertices; ++ki) + { + Vector3D xyz(vertices[3*ki], vertices[3*ki+1], vertices[3*ki+2]); + shared_ptr<RevEngPoint> currpt(new RevEngPoint(xyz, -1)); + currpt->setIndex(ki); + tri_sf->addEntry(currpt); + } + + for (size_t ki=0; ki<ntriangles; ++ki) + { + ftSamplePoint* pt1 = (*tri_sf)[triangles[3*ki]]; + ftSamplePoint* pt2 = (*tri_sf)[triangles[3*ki+1]]; + ftSamplePoint* pt3 = (*tri_sf)[triangles[3*ki+2]]; + pt1->addTriangle(pt2, pt3); + pt2->addTriangle(pt3, pt1); + pt3->addTriangle(pt1, pt2); + } +\endverbatim +\link Go::RevEngPoint RevEngPoint\endlink represents a triangulation vertex and is inherited +from \link Go::ftSamplePoint ftSamplePoint\endlink. RevEngPoint is enhanced with information +such as estimated surface normal and curvature as well as associated functionality. + +\section re_sec2 Overview +The reverse engineering process is organized as a sequence of operations that together +consistute a work flow. The process is as follows: + + * <ol> + * <li> Enhance points + * <li> Classify points according to Gauss and mean curvature + * <li> Segment point cloud into regions + * <li> Surface creation + * <li> Compute global properties such as main axes and update surfaces accordingly + * <li> Edge creation + * <li> Define blend surfaces + * <li> Trim surfaces with respect to identified edges, blend surfaces and adjacent regions + * <li> Create CAD model + +Point 4 to 6 are repeated three times, each time differently. The process +is automated, but organized as a sequence of commands to RevEng. This allows for storing +the state at a number of locations to resume the computation at a convenient time. Note that +storing and reading the state can be time consuming. In the following, we will describe +the process in some detail. The figure below shows a triangulated surface with +400 thousand vertices. This data set will be used to illustrate the reverse +engineering process. + +\image html Tarn_init.gif "Triangulated surface" width=600px + +\section re_sec3 Workflow +The first function to call is RevEng::enhancePoints. The points are approximated by a surface +in a local neighbourhood. Surface normal and principal curvature estimates are +computed from this surface. Approximation errors are registered and used to set an +approximation tolerance for the proceeding computations. An additional surface normal is +computed from the triangulation. The two versions of the surface normal have different +pros and cons, and both are used in the computations. + +Classification is performed in RevEng::classifyPoints. It is based on the size and +sign of estimated Gauss and mean curvature in the points. Very small curvature values are +deciphered as zero. A small curvature radius compared to the average distance between +triangle vertices indicates that the point is a part of an edge. The expected typical +measured objects has rounded edges. Thus, edge detection not a prioritized topic in the current version of the +functionality. As the initial triangulation may lack smoothness, the curvature +information is somewhat unstable, but still appropriate for recognizing significant +regions suitable for being represented by one surface. In the image below, pink colour +indicates that the area around a point is classified as flat, green and orange points +have Gauss curvature close to zero while the remaining colours indicate some +curvature. + +\image html Tarn_classify.gif "Vertices coloured according to curvature properties" width=600px + +Next, the approximation tolerance is set by the call +RevEng::setApproximationTolerance based on information from the preceeding computations. +Alternatively, the application can use the +function RevEng::setApproxTol(double tol) if more control is preferred. As the given +point cloud is expected to be noisy, it is only required that a majority points associated +to a surface will be fit by the surface within this tolerance. There are also requirements on the average approximation error and surface normal direction. + +RevEng::segmentIntoRegions collects connected groups of points with the same classification. +Identified edge points are excluded. This is a two-stage process. First connected points +with the same classification are grouped, then small groups are merged with their +neighbour if feasible. Each group is stored in an instance of \link Go::RevEngRegion RevEngRegion\endlink. In the image below, the individual groups of some size are given +separate colours. Very small groups are shown in black. + +\image html Tarn_segment.gif "Segmented point cloud" width=800px + +The first surface creation is performed in RevEng::initialSurfaces. Regions with a +significant number of points are selected and tentatively fitted by a plane, +a cylinder or a cone. As the point classification can be misleading several +attempts are made and the best fit is selected if it satisfies the accuracy +requirements. Simultanously, points that are found to belong to other surfaces are +dismissed from the region. For our test example, only regions with more than 1357 +points are considered for surface creation. This number is estimated from the +current region sizes. The surfaces are represented as +\link Go::ParamSurface ParamSurface\endlink and embedded in +\link Go::Hedgeurface HedgeSurface\endlink, which is inherited from +\link Go::ftEdge ftEdge\endlink. The collection of HedgeSurfaces are owned by +the RevEng entity, but each surface is linked to the associated RevEngRegion. +The result of the first surface creation for our test case is shown in the image below. + +\image html Tarn_initsurf.gif "The first surfaces, associationed points and main regions" width=800px + +The model is still incomplete. Some, even major, surfaces are missing. Transition zones +are missing and the surfaces don't have any matching directions. Another region growing is +performed in RevEng::growSurfaces, this time with the existence of some surfaces where +the distance between the points of a region and the surface of the adjacent region +can be measured. Next an identification of similar plane normals and rotational surface +axis is performed in RevEng::updateAxesAndSurfaces. Surfaces with almost identical +axes are updated to be consistent. If this implies a major detoriation of the +surface accuracy, the update is dismissed. A coordinate system for the model is +defined. + +The first edge recognition is performed in RevEng::firstEdges. Adjacent and almost +adjacent surfaces are intersected and the intersection curve is stored in +\link Go::RevEngEdge RevEngEdge\endlink along with nearby regions. These regions is +associated with the blend surface for whom the edge is a place holder. The edge +also contains some context information. In the figure below, we see that some +edges are still missing and that the edges don't join up. The main cylindrical surface +and the middle plane meets in five different edges. One is split at the seam of the +cylinder. + +\image html Tarn_edges1.gif "The first edges and associationed points" width=600px + +The first sequence of point 4 to 6 in the process overview is completed. Now +RevEng::surfaceCreation is applied to continue the surface recognition. At this stage, +it is also possible to recognize spheres and torii. As in the first surface +recognition pass, more than one primary surface can be fitted to the points, and +the best fit is choosen if accurate enough. Some regions may be composed by several sub +groups of points that can be associated one surface. The identified model +coordinate system provides a tool to split these regions into consistent parts. +Adjacent surfaces with the same characteristics are merged and the region structure +is simplified further by including small regions into adjacent ones when possible. +The figure below shows the 16 surfaces identified in the example model and the +regions associated to these surfaces. + +\image html Tarn_surfaces2.gif "Updated surface structure and associated regions" width=600px + +RevEng::adaptToMainAxis updates the axis information obtained by updateAxesAndSurfaces +and complements information on axis direction with axis position. After harmonazing +the surfaces with respect to updated global information, possible missing edges are +computed. + +At this stage the major surfaces and associated candidate blends are expected to +be indentified but there may still be unidentified smaller surfaces. Curvature +information and point classification become unstable close to edges in the model and +the restriction on number of points to initiate surface fitting lead to a high +possibility of unrecognized surfaces. In RevEng::smallRegionSurfaces adjacent region +fragments are collected with the aid of global information. Such merged regions are +fitted with planes, cylinders and cones if applicable. The region structure may +be updated by merging adjacent regions into those associated with the new surfaces and +by merging surfaces, and associated regions, representing the same feature. Additional +edges may be defined. + +RevEng::manageBlends1 computed blend surface associated to the collected RevEngEdges. +The blend surfaces will either be cylinders or torii and some coordination of blend +radii is performed. Depending on the actual configuration of the adjacent surfaces, +some gaps or overlaps may occur. The current state for our example model is +visualized in the figure below, first all surfaces +including blends, then the large cylinder is removed for better visibility of the +blend surfaces and finally a detail is emphasized. + +\image html Tarn_blend1.gif "Surfaces with edge blends" width=800px + +RevEng::manageBlends2 bounds the blend surfaces in the blend direction and defines +corresponding trimming curves represented as \link Go::ftEdge ftEdge\endlink and +stored in the blend region. The +geometry representation of the trimming curves are stored in an instance of +\link Go::CurveOnSurface CurveOnSurface\endlink having +curves both in geometry and parameter space. The corresponding curves in the +surfaces being blended are also computed. + +Edge blend surfaces will often meet in a corner blend. Configurations resulting in +torus corners and some 4-sided free form (spline) corners are supported. Additional +trimming curves are added to the associated regions. The figure below shows, in the +first picture, all surfaces including blends and corner blends. In the following +pictures some surfaces are removed for visibility. + +\image html Tarn_blend2.gif "Surfaces with edge and corner blends" width=800px + +RevEng::trimSurfaces arranges the identified trimming curves for each surface in +loops and compute bounded surfaces. The figures below illustrate the procedure for +two surfaces in our example case. The points associated to the main cylinder surface +is shown to the left in the first figure along with trimming curves in geometry space. +The curves are extended beyond their real size and must be reduced. This computation +is performed in parameter space. Curves along the cylinder seam is added to the +collection. Then the trimming curves are cut at intersections with the adjacent +curves and arranged in a loop. The parameter curves before and after this modification +are shown in the middle two pictues. To the right, the final trimmed surface and the +modified trimming curves in geometry space are shown. + +\image html Tarn_trim1.gif "Trimming of cylinder surface" width=800px +\image html Tarn_trim2.gif "Trimming of plane" width=800px + +The trimming of the middle planar surface is shown in the figure above. The procedure +is similar to the cylinder case, but in this case we have an internal trimming curve. +This curve is computed as a boundary towards point regions without an associated +surface. The initial triangular surface lacks information in this area, thus the +expected cylindrical surface inside the model is not found. The shape of this +trimming curve is inferior to the ones found by the intersect and blend +procedure and in newer versions it is dismissed during the trimming operation. + + + +\image html Tarn_surface_collection.gif "All trimmed surfaces" width=600px + +The final surface collection is shown in the image above. RevEng::createModel +finalizes the work flow. Adjacency analysis is performed using functionality in +\link Go::SurfaceModel SurfaceModel\endlink and \ref topology. The final model can be +exported in a \link Go::CompositeModelFileHandler g22-file\endlink. + +\section re_sec4 Workflow summary - implementation +The workflow described above is implemented through a number of calls to functions in +the reverse engineering workflow RevEng. The function calls are listed below, and all +must be executed. +- RevEng::Reveng(shared_ptr<ftPointSet> triangulation) +- RevEng::enhancePoints() * +- RevEng::classifyPoints() * +- RevEng::setApproxTolerance() / RevEng::setApproxTol(double tolerance) +- RevEng::segmentIntoRegions() * +- RevEng::initialSurfaces() * +- RevEng::growSurfaces() * +- RevEng::updateAxesAndSurfaces() * +- RevEng::firstEdges() * +- RevEng::surfaceCreation() * +- RevEng::adaptToMainAxis() * +- RevEng::smallRegionSurfaces() * +- RevEng::manageBlends1() * +- RevEng::manageBlends2() +- RevEng::trimSurfaces() +- shared_ptr<SurfaceModel> RevEng::createModel() + +The workflow is automatic, the only possible current interaction by the application is +to set the tolerance. However, more user interaction is expected to be preferable. +Then user interaction can be used to perform quality control the type of surfaces recognized and +to enable regularization of the model with respect to for instance parallelity, +orthogonality and symmetry. This type of interference can in future versions of the +work flow be included between the calls to RevEng functions. + +The workflow can be stopped and started at a number of stages. The possibilities +are marked with a star in the list above. To stop the execution after for instance +initialSurfaces and restart at a later stage. To store the required information, +the procedure is: +\verbatim + RevEng reveng; + std::ofstream of("initial_surface_stage.txt"); + of << SURFACEONE << std::endl; + reveng.storeGrownRegions(of); +\endverbatim + +To restart: +\verbatim + std::ifstream is(char *data_file); + int stage; + is >> stage; + reveng.readGrownRegions(is); + if (stage <= SURFACEONE) + { + reveng.growSurfaces(); + + // Continue with the remaining functions + } +\endverbatim + +Suggested flags for the stages are: +\verbatim + enum + { + ENHANCED, CLASSIFIED, SEGMENTED, SURFACEONE, GROWONE, UPDATEONE, EDGESONE, SURFACETWO, UPDATETWO, SURFACETHREE, BLENDONE + }; +\endverbatim +Note that storing and reading the execution stage may be time consuming. + +Debug information can be fetched from RevEng after the definition of regions, that +means after executing segmentIntoRegions(), by calling +\verbatim + void writeRegionStage(std::ostream& of, std::ostream& ofm, std::ostream& ofs) const; + void writeRegionWithSurf(std::ostream& of) const; + void writeEdgeStage(std::ostream& of) const; +\endverbatim +writeRegionStage will write points and surfaces organized in regions to three files. +The points of regions with a significant number of points are written to "of" +together with possible associated surfaces. Regions with less points are written to +"ofm" and all points from regions with few points are collected and written to "ofs". +writeRegionWithSurf outputs only those regions that has associated points. +writeEdgeStage writes all RevEngEdges and point groups associated to expected blend +surfaces. The debug information can be visualized in \ref viewlib. + + +\section re_sec5 Data structure +The reverse engineering functionality is integrated in GoTools. The main engine is +\link Go::RevEng RevEng\endlink where the workflow is run. RevEng is also the owner of the +data points, structures where data points are organized and computed surfaces +and edges. An overview is given in the figure below. + +\image html datastructure.png "Data structure" width=600px + +The triangulation is represented by an \link Go::ftPointSet ftPointSet\endlink +stored in RevEng. Segmented points are orgianized in \link Go::RevEngRegion RevEngRegion\endlink. RevEngRegion contains pointers to \link Go::RevEngPoint RevEngPoint\endlink +inherited from \link Go::ftSamplePoint ftSamplePoint\endlink. The points themselves +are still stored in ftPointSet while the point pointers are moved between regions as +the computation proceedes. Computed surfaces are stored in +\link Go::HedgeSurface HedgeSurface\endlink, which again is stored in RevEng. A +surface is connected to one region, while a region may have a surface connected. +HedgeSurface is inherited from \link Go::ftSurface ftSurface\endlink, which is +input to the adjacency analysis, see \ref topology. A +\link Go::RevEngEdge RevEngEdge\endlink is computed from two surfaces but linked +to the associated regions. The instance itself is stored in RevEng. RevEngEdge also +contains pointers to regions associated to the foreseen blend surface and to the +blend region collecting these associated regions when the blend surface is created. +\link Go::RevEngUtils RevEngUtils\endlink provides some utility functionality to the +reverse engineering process. +*/ +#endif // _REVERSEENGINEERING_DOXYMAIN_H diff --git a/compositemodel/src/HedgeSurface.C b/compositemodel/src/HedgeSurface.C new file mode 100644 index 00000000..58c95d12 --- /dev/null +++ b/compositemodel/src/HedgeSurface.C @@ -0,0 +1,814 @@ +/* + * Copyright (C) 1998, 2000-2007, 2010, 2011, 2012, 2013 SINTEF ICT, + * Applied Mathematics, Norway. + * + * Contact information: E-mail: tor.dokken@sintef.no + * SINTEF ICT, Department of Applied Mathematics, + * P.O. Box 124 Blindern, + * 0314 Oslo, Norway. + * + * This file is part of GoTools. + * + * GoTools is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * GoTools 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with GoTools. If not, see + * <http://www.gnu.org/licenses/>. + * + * In accordance with Section 7(b) of the GNU Affero General Public + * License, a covered work must retain the producer line in every data + * file that is created or manipulated using GoTools. + * + * Other Usage + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial activities involving the GoTools library without + * disclosing the source code of your own applications. + * + * This file may be used in accordance with the terms contained in a + * written agreement between you and SINTEF ICT. + */ + +#include "GoTools/compositemodel/HedgeSurface.h" +#include "GoTools/compositemodel/RevEngRegion.h" +#include "GoTools/compositemodel/RevEngUtils.h" +#include "GoTools/geometry/ParamSurface.h" +#include "GoTools/geometry/BoundedSurface.h" +#include "GoTools/geometry/ElementarySurface.h" +#include "GoTools/geometry/Plane.h" +#include "GoTools/geometry/Cylinder.h" +#include "GoTools/geometry/Cone.h" +#include "GoTools/geometry/CurveOnSurface.h" +#include "GoTools/geometry/BoundedUtils.h" +#include "GoTools/creators/TrimCrvUtils.h" +#include "GoTools/creators/TrimUtils.h" +#include "GoTools/geometry/Factory.h" +#include "GoTools/geometry/GoTools.h" +#include "GoTools/geometry/ObjectHeader.h" +#include <fstream> + +//#define DEBUG_TRIM + +using namespace Go; +using std::vector; + +// //=========================================================================== +// HedgeSurface::HedgeSurface() +// : ftSurface() +// //=========================================================================== +// { +// } + +//=========================================================================== +HedgeSurface::HedgeSurface() + : ftSurface() +//=========================================================================== +{ +} + +//=========================================================================== +HedgeSurface::HedgeSurface(shared_ptr<ParamSurface> sf, RevEngRegion *region) + : ftSurface(sf, -1) +//=========================================================================== +{ + regions_.push_back(region); + bbox_ = region->boundingBox(); + surf_code_ = SURF_TYPE_UNDEF; +} + +//=========================================================================== +HedgeSurface::HedgeSurface(shared_ptr<ParamSurface> sf, + vector<RevEngRegion*>& region) + : ftSurface(sf, -1), regions_(region) +//=========================================================================== +{ + if (region.size() > 0) + { + bbox_ = region[0]->boundingBox(); + for (size_t ki=1; ki<region.size(); ++ki) + bbox_.addUnionWith(region[ki]->boundingBox()); + } + surf_code_ = SURF_TYPE_UNDEF; +} + + +//=========================================================================== +HedgeSurface::~HedgeSurface() +//=========================================================================== +{ +} + +//=========================================================================== +int HedgeSurface::numPoints() +//=========================================================================== +{ + int num = 0; + for (size_t ki=0; ki<regions_.size(); ++ki) + num += regions_[ki]->numPoints(); + return num; + } + +//=========================================================================== +ClassType HedgeSurface::instanceType(int& code) +//=========================================================================== +{ + code = surf_code_; + ClassType type = surface()->instanceType(); + if (type == Class_BoundedSurface) + { + shared_ptr<ParamSurface> surf = surface(); + shared_ptr<BoundedSurface> bdsurf = + dynamic_pointer_cast<BoundedSurface,ParamSurface>(surf); + type = bdsurf->underlyingSurface()->instanceType(); + } + return type; +} + + +//=========================================================================== +bool HedgeSurface::updateSurfaceWithAxis(Point axis[3], int ix, double tol, + double angtol) +//=========================================================================== +{ + bool updated = false; + int code = -1; + ClassType type = instanceType(code); + if (type == Class_Plane) + updated = updatePlaneWithAxis(axis, ix, tol, angtol); + else if (type == Class_Cylinder) + updated = updateCylinderWithAxis(axis, ix, tol, angtol); + + return updated; +} + +//=========================================================================== +bool HedgeSurface::updatePlaneWithAxis(Point axis[3], int ix, double tol, + double angtol) +//=========================================================================== +{ + shared_ptr<Plane> init_plane = dynamic_pointer_cast<Plane,ParamSurface>(surf_); + if (!init_plane.get()) + return false; + Point loc = init_plane->location(); + Point mid(0.0, 0.0, 0.0); + double wgt = 1.0/(double)numPoints(); + for (size_t ki=0; ki<regions_.size(); ++ki) + for (auto it=regions_[ki]->pointsBegin(); it!=regions_[ki]->pointsEnd(); ++it) + { + Vector3D pos0 = (*it)->getPoint(); + Point pos(pos0[0], pos0[1], pos0[2]); + Point vec = pos - loc; + Point pos2 = loc + (vec*axis[ix])*axis[ix]; + mid += wgt*pos2; + } + + shared_ptr<Plane> plane(new Plane(mid, axis[ix], axis[(ix+1)%3])); + + // Check accuracy + bool updated = checkAccuracyAndUpdate(plane, tol, angtol); + return updated; +} + +//=========================================================================== +bool HedgeSurface::updateCylinderWithAxis(Point axis[3], int ix, double tol, + double angtol) +//=========================================================================== +{ + vector<pair<vector<RevEngPoint*>::iterator, + vector<RevEngPoint*>::iterator> > points; + for (size_t ki=0; ki<regions_.size(); ++ki) + points.push_back(std::make_pair(regions_[ki]->pointsBegin(), + regions_[ki]->pointsEnd())); + + Point pos; + double rad; + Point low = bbox_.low(); + Point high = bbox_.high(); + RevEngUtils::computeCylPosRadius(points, low, high, axis[ix], axis[(ix+1)%3], + axis[(ix+2)%3], pos, rad); + + // Select x-axis + shared_ptr<ElementarySurface> elem = + dynamic_pointer_cast<ElementarySurface,ParamSurface>(surf_); + int ix2 = (ix+2)%3; + if (elem.get()) + { + Point dir = elem->direction2(); + double ang1 = dir.angle(axis[(ix+1)%3]); + ang1 = std::min(ang1, M_PI-ang1); + double ang2 = dir.angle(axis[(ix+2)%3]); + ang2 = std::min(ang1, M_PI-ang2); + if (ang1 < ang2) + ix2 = (ix+1)%3; + } + shared_ptr<Cylinder> cyl(new Cylinder(rad, pos, axis[ix], axis[ix2])); + + // Check accuracy + bool updated = checkAccuracyAndUpdate(cyl, tol, angtol); + return updated; +} + +//=========================================================================== +bool HedgeSurface::checkAccuracyAndUpdate(shared_ptr<ParamSurface> surf, + double tol, double angtol) +//=========================================================================== +{ + bool updated = false; + vector<vector<pair<double, double> > > dist_ang(regions_.size()); + vector<double> maxd(regions_.size()), avd(regions_.size()); + vector<int> num_in(regions_.size()); + vector<int> num2_in(regions_.size()); + vector<vector<double> > parvals(regions_.size()); + int all_in = 0; + double avd_all = 0.0; + double fac = 1.0/(double)numPoints(); + vector<int> sfflag(regions_.size(), NOT_SET); + bool sfOK = true; + bool cyllike = (surf->instanceType() == Class_Cylinder || + surf->instanceType() == Class_Cone); + for (size_t ki=0; ki<regions_.size(); ++ki) + { + vector<RevEngPoint*> inpt, outpt; + RevEngUtils::distToSurf(regions_[ki]->pointsBegin(), regions_[ki]->pointsEnd(), + surf, tol, maxd[ki], avd[ki], num_in[ki], num2_in[ki], + inpt, outpt, parvals[ki], dist_ang[ki], angtol); + all_in += num_in[ki]; + avd_all += fac*regions_[ki]->numPoints()*avd[ki]; + sfflag[ki] = regions_[ki]->defineSfFlag(0, tol, num_in[ki], num2_in[ki], + avd[ki], cyllike); + if (sfflag[ki] == NOT_SET) + sfOK = false; + } + + if (sfOK) //all_in > numPoints()/2 && avd_all <= tol) + { + updated = true; + for (size_t ki=0; ki<regions_.size(); ++ki) + { + size_t kj=0; + for (auto it=regions_[ki]->pointsBegin(); it!=regions_[ki]->pointsEnd(); + ++it, ++kj) + { + (*it)->setPar(Vector2D(parvals[ki][2*kj],parvals[ki][2*kj+1])); + (*it)->setSurfaceDist(dist_ang[ki][kj].first, dist_ang[ki][kj].second); + } + regions_[ki]->setAccuracy(maxd[ki], avd[ki], num_in[ki], num2_in[ki]); + regions_[ki]->computeDomain(); + regions_[ki]->setSurfaceFlag(sfflag[ki]); + } + + replaceSurf(surf); + } + return updated; +} + +//=========================================================================== +bool HedgeSurface::isCompatible(HedgeSurface* other, double angtol, double approx_tol, ClassType& type, double& score) +//=========================================================================== +{ + score = std::numeric_limits<double>::max(); + int code1 = -1, code2 = -1; + ClassType type1 = instanceType(code1); + ClassType type2 = other->instanceType(code2); + + shared_ptr<ParamSurface> surf1 = surface(); + shared_ptr<ElementarySurface> psurf1 = + dynamic_pointer_cast<ElementarySurface,ParamSurface>(surf1); + if (!psurf1.get()) + { + shared_ptr<BoundedSurface> bdsf1 = + dynamic_pointer_cast<BoundedSurface,ParamSurface>(surf1); + if (bdsf1.get()) + { + surf1 = bdsf1->underlyingSurface(); + psurf1 = dynamic_pointer_cast<ElementarySurface,ParamSurface>(surf1); + } + } + + shared_ptr<ParamSurface> surf2 = other->surface(); + shared_ptr<ElementarySurface> psurf2 = + dynamic_pointer_cast<ElementarySurface,ParamSurface>(surf2); + if (!psurf2.get()) + { + shared_ptr<BoundedSurface> bdsf2 = + dynamic_pointer_cast<BoundedSurface,ParamSurface>(surf2); + if (bdsf2.get()) + { + surf2 = bdsf2->underlyingSurface(); + psurf2 = dynamic_pointer_cast<ElementarySurface,ParamSurface>(surf2); + } + } + + if (!psurf1.get()) + { + RevEngRegion *preg = 0; + int numpt = 0; + int nreg = numRegions(); + for (int ka=0; ka<nreg; ++ka) + { + RevEngRegion *reg = getRegion(ka); + if (reg->hasBaseSf()) + { + double maxdp, avdp; + int num_inp, num2_inp; + int curr_numpt = reg->numPoints(); + reg->getBaseDist(maxdp, avdp, num_inp, num2_inp); + if (avdp < approx_tol && num_inp > curr_numpt/2 && curr_numpt > numpt) + { + preg = reg; + numpt = curr_numpt; + } + } + } + if (preg) + { + psurf1 = + dynamic_pointer_cast<ElementarySurface,ParamSurface>(preg->getBase()); + type1 = preg->getBase()->instanceType(); + } + } + + if (!psurf2.get()) + { + RevEngRegion *preg = 0; + int numpt = 0; + int nreg = other->numRegions(); + for (int ka=0; ka<nreg; ++ka) + { + RevEngRegion *reg = other->getRegion(ka); + if (reg->hasBaseSf()) + { + double maxdp, avdp; + int num_inp, num2_inp; + int curr_numpt = reg->numPoints(); + reg->getBaseDist(maxdp, avdp, num_inp, num2_inp); + if (avdp < approx_tol && num_inp > curr_numpt/2 && curr_numpt > numpt) + { + preg = reg; + numpt = curr_numpt; + } + } + } + if (preg) + { + psurf2 = + dynamic_pointer_cast<ElementarySurface,ParamSurface>(preg->getBase()); + type2 = preg->getBase()->instanceType(); + } + } + + if (!psurf1.get() || !psurf2.get()) + return false; + if (type1 != type2 || code1 != code2) + return false; // Not the same surface type + type = type1; + + Point loc1 = psurf1->location(); + Point loc2 = psurf2->location(); + Point vec1 = psurf1->direction(); + Point vec2 = psurf2->direction(); + double rad1 = psurf1->radius(0.0, 0.0); // Parameters must be set properly for cone + double rad2 = psurf2->radius(0.0, 0.0); + double smallrad1 = psurf1->radius2(0.0, 0.0); + double smallrad2 = psurf2->radius2(0.0, 0.0); + vec1.normalize_checked(); + vec2.normalize_checked(); + + int sgn = (type1 == Class_Plane) ? -1 : 1; + double ang = vec1.angle(vec2); + ang = std::min(ang, M_PI-ang); + + double dlim = (rad1 < 0.0) ? approx_tol : std::max(0.05*rad1, approx_tol); + double anglim = 10.0*angtol; + double eps = 1.0e-8; + if (ang > anglim) + return false; + // if (fabs(rad2-rad1) > dlim && fabs(smallrad2-smallrad1) < eps) + // return false; + if (rad1 >= 0.0 && rad2 >= 0.0 && + fabs(rad2-rad1) > std::min(rad1, rad2) && fabs(smallrad2-smallrad1) < eps) + return false; + else if (smallrad1 > 0.0 && + (rad1 < rad2-smallrad2 || rad1 > rad2+smallrad2 || + rad2 < rad1-smallrad1 || rad2 > rad1+smallrad1)) + return false; + + double pdist1 = 0.0, pdist2 = 0.0; + if (type1 == Class_Plane) + { + Point loc2_0 = loc2 - ((loc2-loc1)*vec1)*vec1; + Point loc1_0 = loc1 - ((loc2-loc1)*vec2)*vec2; + pdist1 = loc2.dist(loc2_0); + pdist2 = loc1.dist(loc1_0); + pdist1 = pdist2 = std::min(pdist1, pdist2); + if (pdist1 > 2.0*dlim || pdist2 > 2.0*dlim) + return false; + } + else if (type1 == Class_Cylinder) + { + Point loc2_0 = loc1 + ((loc2-loc1)*vec1)*vec1; + pdist1 = loc2.dist(loc2_0); + if (pdist1 + fabs(rad2-rad1) > std::min(rad1, rad2)) + // if (pdist1 > dlim) + return false; + } + else if (type1 == Class_Torus) + { + pdist1 = loc1.dist(loc2); + if (pdist1 > 2.0*dlim || pdist2 > 2.0*dlim) + return false; + } + + score = 10.0*ang + fabs(rad2-rad1) + fabs(smallrad2-smallrad1) + + pdist1 + pdist2; + return true; +} + +//=========================================================================== +bool HedgeSurface::hasBaseSf() +//=========================================================================== +{ + for (size_t ki=0; ki<regions_.size(); ++ki) + if (regions_[ki]->hasBaseSf()) + return true; + return false; +} + +//=========================================================================== +void HedgeSurface::ensureSurfaceBounded() +//=========================================================================== +{ + shared_ptr<ParamSurface> surf = surface(); + shared_ptr<ElementarySurface> elemsf = + dynamic_pointer_cast<ElementarySurface,ParamSurface>(surf); + if (!elemsf.get()) + return; // Always bounded + if (!elemsf->isBounded()) + { + double diag = bbox_.low().dist(bbox_.high()); + if (elemsf->instanceType() == Class_Plane) + elemsf->setParameterBounds(-0.6*diag, -0.6*diag, 0.6*diag, 0.6*diag); + else if (elemsf->instanceType() == Class_Cylinder) + { + shared_ptr<Cylinder> cyl = + dynamic_pointer_cast<Cylinder,ElementarySurface>(elemsf); + cyl->setParamBoundsV(-0.6*diag, 0.6*diag); + } + else if (elemsf->instanceType() == Class_Cone) + { + shared_ptr<Cone> cone = + dynamic_pointer_cast<Cone,ElementarySurface>(elemsf); + cone->setParamBoundsV(-0.6*diag, 0.6*diag); + } + } +} + +//=========================================================================== +bool HedgeSurface::isTangential(HedgeSurface* surf) +//=========================================================================== +{ + return false; // To be implemented properly +} + +//=========================================================================== +void HedgeSurface::doTrim(vector<shared_ptr<CurveOnSurface> >& int_cvs, + shared_ptr<BoundedSurface>& bdsf, + double tol, + vector<shared_ptr<HedgeSurface> >& added_sfs) +//=========================================================================== +{ + vector<shared_ptr<BoundedSurface> > trim_sfs; + if (int_cvs.size() > 0) + { + trim_sfs = BoundedUtils::splitWithTrimSegments(bdsf, int_cvs, tol); + } + + std::ofstream of1("curr_trim.g2"); + for (size_t ki=0; ki<trim_sfs.size(); ++ki) + { + trim_sfs[ki]->writeStandardHeader(of1); + trim_sfs[ki]->write(of1); + } + + if (trim_sfs.size() <= 1) + { + // Do something to complement the intersection results + int stop_break1 = 1; + } + + // Assume, for the time being, that no region is split between sub surfaces + vector<shared_ptr<BoundedSurface> > valid_trim; + vector<vector<RevEngRegion*> > regs; + for (size_t ki=0; ki<trim_sfs.size(); ++ki) + { + vector<RevEngRegion*> curr_regs; + for (size_t kj=0; kj<regions_.size(); ++kj) + { + int numpt = regions_[kj]->numPoints(); + int inside = 2; + for (int ka=0; ka<numpt; ++ka) + { + RevEngPoint *pt = regions_[kj]->getPoint(ka); + Vector2D parpt = pt->getPar(); + inside = trim_sfs[ki]->inDomain2(parpt[0], parpt[1]); + if (inside != 2) + break; // Not on a boundary + } + if (inside == 1) + curr_regs.push_back(regions_[kj]); + } + if (curr_regs.size() > 0) + { + valid_trim.push_back(trim_sfs[ki]); + regs.push_back(curr_regs); + } + } + + for (size_t ki=1; ki<valid_trim.size(); ++ki) + { + shared_ptr<HedgeSurface> hedge(new HedgeSurface(valid_trim[ki], regs[ki])); + for (size_t kj=0; kj<regs[ki].size(); ++kj) + { + (void)removeRegion(regs[ki][kj]); + regs[ki][kj]->setHedge(hedge.get()); + } + added_sfs.push_back(hedge); + } + if (valid_trim.size() > 0) + replaceSurf(valid_trim[0]); + + + int stop_break = 1; +} + +//=========================================================================== +bool HedgeSurface::removeRegion(RevEngRegion* reg) +//=========================================================================== +{ + auto it = std::find(regions_.begin(), regions_.end(), reg); + if (it != regions_.end()) + { + regions_.erase(it); + if (regions_.size() > 0) + { + bbox_ = regions_[0]->boundingBox(); + for (size_t ki=1; ki<regions_.size(); ++ki) + bbox_.addUnionWith(regions_[ki]->boundingBox()); + } + } + return false; +} + +//=========================================================================== +void HedgeSurface::addRegion(RevEngRegion* reg) +//=========================================================================== +{ + regions_.push_back(reg); + if (bbox_.dimension() == 0) + bbox_ = reg->boundingBox(); + else + bbox_.addUnionWith(reg->boundingBox()); +} + +//=========================================================================== +void HedgeSurface::limitSurf(double diag) +//=========================================================================== +{ + shared_ptr<ParamSurface> surf = surface(); + shared_ptr<ElementarySurface> elemsf = + dynamic_pointer_cast<ElementarySurface,ParamSurface>(surf); + if (elemsf.get() && !elemsf->isBounded()) + { + if (diag < 0.0) + diag = bbox_.low().dist(bbox_.high()); + double domain[4]; + regions_[0]->getDomain(domain); + double midu = 0.5*(domain[0]+domain[1]); + double midv = 0.5*(domain[2]+domain[3]); + double fac = 1.0; + shared_ptr<Plane> plane = dynamic_pointer_cast<Plane,ParamSurface>(surf); + shared_ptr<Cylinder> cyl = dynamic_pointer_cast<Cylinder,ParamSurface>(surf); + shared_ptr<Cone> cone = dynamic_pointer_cast<Cone,ParamSurface>(surf); + if (plane.get()) + plane->setParameterBounds(midu-fac*diag, midv-fac*diag, + midu+fac*diag, midv+fac*diag); + else if (cyl.get()) + cyl->setParamBoundsV(midv-fac*diag, midv+fac*diag); + else if (cone.get()) + cone->setParamBoundsV(midv-fac*diag, midv+fac*diag); + } +} + +//=========================================================================== +bool HedgeSurface::trimWithPoints(double aeps) +//=========================================================================== +{ + // Extract data points + int del = 5; + int num_pts = numPoints(); + if (num_pts < 10) + return false; + vector<double> data(del*num_pts); + int num_reg = numRegions(); + vector<double> extent(2*del); // Limits for points in all coordinates + for (int ki=0, kj=0; ki<num_reg; ++ki) + { + RevEngRegion *reg = getRegion(ki); + int npts = reg->numPoints(); + for (int kr=0; kr<npts; ++kr, ++kj) + { + RevEngPoint *pt = reg->getPoint(kr); + Vector2D uv = pt->getPar(); + Vector3D xyz = pt->getPoint(); + data[del*kj] = uv[0]; + data[del*kj+1] = uv[1]; + data[del*kj+2] = xyz[0]; + data[del*kj+3] = xyz[1]; + data[del*kj+4] = xyz[2]; + } + } + for (int kj=0; kj<del; ++kj) + extent[2*kj] = extent[2*kj+1] = data[kj]; + for (int ki=1; ki<num_pts; ++ki) + for (int kj=0; kj<del; ++kj) + { + extent[2*kj] = std::min(extent[2*kj],data[ki*del+kj]); + extent[2*kj+1] = std::max(extent[2*kj+1],data[ki*del+kj]); + } + + + // Rough trimming curve + double tol = 1.0e-5; + int max_rec = 1; + int nmb_div = std::min(num_pts/70, 8); //15; + + if (extent[1]-extent[0] < tol || extent[3]-extent[2] < tol) + return false; + // Compute trimming seqence + bool only_outer = true; + vector<vector<double> > seqs; + //TrimUtils trimutil(points2, 1, domain); + TrimUtils trimutil(&data[0], num_pts, del-2, &extent[0]); + trimutil.computeTrimSeqs(max_rec, nmb_div, seqs, only_outer); + + // Compute trimming loop + // First extract parts of the trimming sequences following iso trim curves + double udel, vdel; + trimutil.getDomainLengths(udel, vdel); + + int nmb_loops = only_outer ? std::min(1,(int)seqs.size()) : (int)seqs.size(); + vector<vector<vector<double> > > all_seqs(nmb_loops); + if (nmb_loops == 0) + return false; + for (int kh=0; kh<nmb_loops; ++kh) + all_seqs[kh].push_back(seqs[kh]); + + int nmb_match = 4; + double eps = std::max(udel, vdel); + vector<vector<shared_ptr<CurveOnSurface> > > loop(nmb_loops); + for (int kh=0; kh<nmb_loops; ++kh) + { + for (int kj=0; kj<4; ++kj) + { + int ix = (kj < 2) ? 0 : 1; + for (int ki=0; ki<(int)all_seqs[kh].size();) + { + vector<vector<double> > split_seqs1 = + TrimCrvUtils::extractConstParSeqs(all_seqs[kh][ki], ix, + extent[kj], nmb_match, + tol, eps); + if (split_seqs1.size() > 1 || split_seqs1[0].size() == 4) + { + all_seqs[kh].erase(all_seqs[kh].begin()+ki); + all_seqs[kh].insert(all_seqs[kh].begin()+ki, + split_seqs1.begin(), split_seqs1.end()); + ki += (int)split_seqs1.size(); + } + else + ++ki; + } + } + + // Split the remaining sequences from the outer loop in kinks + double kink_tol = 5e-01; // 0.1 deg => 5.7 degrees. + vector<vector<double> > split_seqs; + for (size_t ki=0; ki<all_seqs[kh].size(); ++ki) + { + vector<vector<double> > curr_seqs = + TrimCrvUtils::splitCurvePointsInKinks(all_seqs[kh][ki], kink_tol); + split_seqs.insert(split_seqs.end(), curr_seqs.begin(), curr_seqs.end()); + } + + // Ensure a closed trimming loop + TrimCrvUtils::makeConnectedLoop(split_seqs, tol); + + // Create trimming curves + const int par_dim = 2; + const int max_iter = 5; + vector<shared_ptr<SplineCurve> > par_cvs; + for (size_t ki = 0; ki < split_seqs.size(); ++ki) + { + shared_ptr<SplineCurve> spline_cv_appr_2d + (TrimCrvUtils::approximateTrimPts(split_seqs[ki], par_dim, eps, + max_iter)); + par_cvs.push_back(spline_cv_appr_2d); + } + + // The curve should be CCW. + // Assume one outer and the rest inner (this is not necessarily true) + const double int_tol = 1e-06; + vector<shared_ptr<ParamCurve> > par_cvs2(par_cvs.begin(), par_cvs.end()); + bool loop_is_ccw = LoopUtils::loopIsCCW(par_cvs2, eps, int_tol); + if ((kh==0 && !loop_is_ccw) || (kh>0 && loop_is_ccw)) + { + //MESSAGE("We should change direction of the loop cv!"); + for (size_t ki = 0; ki < par_cvs.size(); ++ki) + { + par_cvs[ki]->reverseParameterDirection(); + } + reverse(par_cvs.begin(), par_cvs.end()); + } + loop[kh].resize(par_cvs.size()); + for (size_t ki = 0; ki < par_cvs.size(); ++ki) + { + loop[kh][ki] = + shared_ptr<CurveOnSurface>(new CurveOnSurface(surface(), par_cvs[ki], true)); + } + } +#ifdef DEBUG_TRIM + std::ofstream fileout("trimcrvs.g2"); + for (size_t kh=0; kh<loop.size(); ++kh) + { + for (size_t kr=0; kr<loop[kh].size(); ++kr) + { + loop[kh][kr]->parameterCurve()->writeStandardHeader(fileout); + loop[kh][kr]->parameterCurve()->write(fileout); + } + } + if (del != 3) + { + fileout << "400 1 0 0" << std::endl; + fileout << num_pts << std::endl; + for (int ka=0; ka<num_pts; ++ka) + { + fileout << data[ka*del] << " " << data[ka*del+1] << " 0.0" << std::endl; + } + } +#endif + shared_ptr<BoundedSurface> bdsf(new BoundedSurface(surface(), loop, aeps)); + replaceSurf(bdsf); + + return true; +} + +//=========================================================================== +void HedgeSurface::store(std::ostream& os) const +//=========================================================================== +{ + os << id_ << " " << surf_code_ << std::endl; + surf_->writeStandardHeader(os); + surf_->write(os); + int profile = (profile_.get()) ? 1 : 0; + os << profile << std::endl; + if (profile_.get()) + { + profile_->writeStandardHeader(os); + profile_->write(os); + os << sweep1_ << " " << sweep2_ << std::endl; + } +} + +//=========================================================================== +void HedgeSurface::read(std::istream& is) +//=========================================================================== +{ + GoTools::init(); + is >> id_ >> surf_code_; + ObjectHeader header; + header.read(is); + shared_ptr<GeomObject> obj(Factory::createObject(header.classType())); + obj->read(is); + surf_ = dynamic_pointer_cast<ParamSurface,GeomObject>(obj); + int profile; + is >> profile; + if (profile) + { + ObjectHeader header2; + header2.read(is); + shared_ptr<GeomObject> obj2(Factory::createObject(header2.classType())); + obj2->read(is); + profile_ = dynamic_pointer_cast<SplineCurve,GeomObject>(obj); + sweep1_ = Point(3); + sweep1_.read(is); + sweep2_ = Point(3); + sweep2_.read(is); + } +} diff --git a/compositemodel/src/ImplicitApprox.C b/compositemodel/src/ImplicitApprox.C new file mode 100644 index 00000000..9f507cf2 --- /dev/null +++ b/compositemodel/src/ImplicitApprox.C @@ -0,0 +1,940 @@ +/* + * Copyright (C) 1998, 2000-2007, 2010, 2011, 2012, 2013 SINTEF ICT, + * Applied Mathematics, Norway. + * + * Contact information: E-mail: tor.dokken@sintef.no + * SINTEF ICT, Department of Applied Mathematics, + * P.O. Box 124 Blindern, + * 0314 Oslo, Norway. + * + * This file is part of GoTools. + * + * GoTools is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * GoTools 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with GoTools. If not, see + * <http://www.gnu.org/licenses/>. + * + * In accordance with Section 7(b) of the GNU Affero General Public + * License, a covered work must retain the producer line in every data + * file that is created or manipulated using GoTools. + * + * Other Usage + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial activities involving the GoTools library without + * disclosing the source code of your own applications. + * + * This file may be used in accordance with the terms contained in a + * written agreement between you and SINTEF ICT. + */ + +#include "GoTools/compositemodel/ImplicitApprox.h" +#include "GoTools/compositemodel/RevEngPoint.h" +#include "GoTools/implicitization/ImplicitizePointCloudAlgo.h" +#include "GoTools/geometry/PointCloud.h" +#include "GoTools/geometry/ObjectHeader.h" +#include "GoTools/geometry/PointCloud.h" +#include "GoTools/geometry/LineCloud.h" +#include "GoTools/geometry/SweepSurfaceCreator.h" +#include "GoTools/geometry/SplineCurve.h" +#include "GoTools/geometry/SplineSurface.h" +#include "GoTools/utils/BoundingBox.h" +#include "GoTools/compositemodel/SurfaceModel.h" +#include "GoTools/compositemodel/CompositeModelFactory.h" +#include "GoTools/compositemodel/ftPlane.h" +#include "GoTools/compositemodel/ftCurve.h" +#include "GoTools/implicitization/BernsteinPoly.h" +#include "newmat.h" +#include "newmatap.h" +#include "sisl.h" +#include <fstream> + +using namespace Go; +using std::vector; + +//=========================================================================== +ImplicitApprox::ImplicitApprox() + : eps_(1.0e-12) +//=========================================================================== +{ +} + +//=========================================================================== +ImplicitApprox::~ImplicitApprox() +//=========================================================================== +{ +} + +//=========================================================================== +void ImplicitApprox::approx(vector<RevEngPoint*> points, int degree) +//=========================================================================== +{ + // Extract xyz values + vector<Vector3D> xyz(points.size()); + for (size_t ki=0; ki<points.size(); ++ki) + xyz[ki] = points[ki]->getPoint(); + + PointCloud3D pointset(xyz); + + // Implicitize + degree_ = degree; + ImplicitizePointCloudAlgo implicitize(pointset, degree); + implicitize.perform(); + + // Get result + implicitize.getResultData(implicit_, bc_, sigma_min_); + + // Differentiate + Vector4D bdir1(1.0, 0.0, 0.0, 0.0); + Vector4D bdir2(0.0, 1.0, 0.0, 0.0); + Vector4D bdir3(0.0, 0.0, 1.0, 0.0); + Vector4D bdir4(0.0, 0.0, 0.0, 1.0); + implicit_.deriv(1, bdir1, deriv1_); + implicit_.deriv(1, bdir2, deriv2_); + implicit_.deriv(1, bdir3, deriv3_); + implicit_.deriv(1, bdir4, deriv4_); + +} + +//=========================================================================== +void ImplicitApprox::approxPoints(vector<Point> points, int degree) +//=========================================================================== +{ + // Extract xyz values + vector<Vector3D> xyz(points.size()); + for (size_t ki=0; ki<points.size(); ++ki) + xyz[ki] = Vector3D(points[ki].begin()); + + PointCloud3D pointset(xyz); + + // Implicitize + degree_ = degree; + ImplicitizePointCloudAlgo implicitize(pointset, degree); + implicitize.perform(); + + // Get result + implicitize.getResultData(implicit_, bc_, sigma_min_); + + // Differentiate + Vector4D bdir1(1.0, 0.0, 0.0, 0.0); + Vector4D bdir2(0.0, 1.0, 0.0, 0.0); + Vector4D bdir3(0.0, 0.0, 1.0, 0.0); + Vector4D bdir4(0.0, 0.0, 0.0, 1.0); + implicit_.deriv(1, bdir1, deriv1_); + implicit_.deriv(1, bdir2, deriv2_); + implicit_.deriv(1, bdir3, deriv3_); + implicit_.deriv(1, bdir4, deriv4_); + +} + +//=========================================================================== +void ImplicitApprox::approx(vector<pair<vector<RevEngPoint*>::iterator, + vector<RevEngPoint*>::iterator> >& points, + int degree) +//=========================================================================== +{ + // Extract xyz values + vector<Vector3D> xyz; + for (size_t kj=0; kj<points.size(); ++kj) + { + for (auto it=points[kj].first; it!=points[kj].second; ++it) + { + Vector3D curr = (*it)->getPoint(); + xyz.push_back(curr); + } + } + PointCloud3D pointset(xyz); + + // Implicitize + degree_ = degree; + ImplicitizePointCloudAlgo implicitize(pointset, degree); + implicitize.perform(); + + // Get result + implicitize.getResultData(implicit_, bc_, sigma_min_); + + // Differentiate + Vector4D bdir1(1.0, 0.0, 0.0, 0.0); + Vector4D bdir2(0.0, 1.0, 0.0, 0.0); + Vector4D bdir3(0.0, 0.0, 1.0, 0.0); + Vector4D bdir4(0.0, 0.0, 0.0, 1.0); + implicit_.deriv(1, bdir1, deriv1_); + implicit_.deriv(1, bdir2, deriv2_); + implicit_.deriv(1, bdir3, deriv3_); + implicit_.deriv(1, bdir4, deriv4_); + +} + +//=========================================================================== +void ImplicitApprox::evaluate(Point& pt, double& val, Point& grad) +//=========================================================================== +{ + Vector3D xyz(pt[0], pt[1], pt[2]); + Vector4D bary = bc_.cartToBary(xyz); + val = implicit_(bary); + double d1 = deriv1_(bary); + double d2 = deriv2_(bary); + double d3 = deriv3_(bary); + double d4 = deriv4_(bary); + Vector4D dv(d1,d2,d3,d4); + Vector4D bary2 = bary+dv; + Vector3D pt2 = bc_.baryToCart(bary2); + Vector3D grad2 = pt2 - xyz; + grad = Point(grad2[0], grad2[1], grad2[2]); +} + +//=========================================================================== +double ImplicitApprox::estimateDist(RevEngPoint* pt) +//=========================================================================== +{ + Vector3D xyz = pt->getPoint(); + Vector4D bary = bc_.cartToBary(xyz); + double dist0 = implicit_(bary); + double d1 = deriv1_(bary); + double d2 = deriv2_(bary); + double d3 = deriv3_(bary); + double d4 = deriv4_(bary); + Vector4D dv(d1,d2,d3,d4); + Vector4D bary2 = bary+dv; + Vector3D pt2 = bc_.baryToCart(bary2); + Vector3D grad = pt2 - xyz; + double len = grad.length(); + double dist = (len > eps_) ? dist0/len : dist0; + + Point norm = pt->getLocFuncNormal(); + Vector3D norm2(norm[0], norm[1], norm[2]); + norm2 *= 100; + Vector3D xyz2 = xyz + norm2; + Vector3D xyz3 = xyz - norm2; + Vector4D bary3 = bc_.cartToBary(xyz2); + Vector4D bary4 = bc_.cartToBary(xyz3); + BernsteinPoly line = implicit_.pickLine(bary3, bary4); + + // Compute zeroes of bernstein polynomial + // First make sisl curve + int ik = degree_ + 1; + vector<double> et(2*ik, 0.0); // Knot vector of line curve + for (int ki=0; ki<ik; ++ki) + et[ik+ki] = 1.0; + vector<double> ecoef(line.coefsBegin(), line.coefsEnd()); + SISLCurve *qc = newCurve(ik, ik, &et[0], &ecoef[0], 1, 1, 1); + double zero = 0.0; + + // Intersect + double eps = 1.0e-6; + int kstat = 0; + int kcrv=0, kpt=0; + double *epar = 0; + SISLIntcurve **intcv = 0; + if (qc) + s1871(qc, &zero, 1, eps, &kpt, &epar, &kcrv, &intcv, &kstat); + if (qc) + freeCurve(qc); + + // Compute cartesian points and curves associated with intersections + double dd = std::numeric_limits<double>::max(); + for (int kr=0; kr<kpt; ++kr) + { + Vector4D barypt = (1.0 - epar[kr])*bary3 + epar[kr]*bary4; + Vector3D pos = bc_.baryToCart(barypt); + double dd2 = xyz.dist(pos); + if (dd2 < dd) + dd = dd2; + } + if (epar) free(epar); + if (intcv) freeIntcrvlist(intcv, kcrv); + return dd; //dist; +} + +//=========================================================================== +bool ImplicitApprox::projectPoint(Point point, Point dir, + Point& projpos, Point& normal) +//=========================================================================== +{ + double len = 100.0; + dir.normalize(); + + Point xdir(1.0, 0.0, 0.0); + Point ydir(0.0, 1.0, 0.0); + Point zdir(0.0, 0.0, 1.0); + double a1 = xdir.angle(dir); + double a2 = ydir.angle(dir); + double a3 = zdir.angle(dir); + Point dir2; + if (a1 > std::min(a2, a3)) + dir2 = xdir; + else if (a2 > a3) + dir2 = ydir; + else + dir2 = zdir; + Point dir3 = dir%dir2; + dir2 = dir%dir3; + dir2.normalize(); + dir3.normalize(); + Point points[3]; + points[0] = point; + points[1] = point + dir2; + points[2] = point + dir3; + + Vector3D proj[3]; + int ka; + for (ka=0; ka<3; ++ka) + { + Vector3D xyz(points[ka].begin()); + Point p1 = points[ka] - len*dir; + Point p2 = points[ka] + len*dir; + + Vector3D cart1(p1.begin()); + Vector3D cart2(p2.begin()); + Vector4D bary1 = bc_.cartToBary(Vector3D(cart1[0], cart1[1], cart1[2])); + Vector4D bary2 = bc_.cartToBary(Vector3D(cart2[0], cart2[1], cart2[2])); + + // Pick line + BernsteinPoly line = implicit_.pickLine(bary1, bary2); + + // Compute zeroes of bernstein polynomial + // First make sisl curve + int ik = degree_ + 1; + vector<double> et(2*ik, 0.0); // Knot vector of line curve + for (int ki=0; ki<ik; ++ki) + et[ik+ki] = 1.0; + vector<double> ecoef(line.coefsBegin(), line.coefsEnd()); + SISLCurve *qc = newCurve(ik, ik, &et[0], &ecoef[0], 1, 1, 1); + double zero = 0.0; + + // Intersect + double eps = 1.0e-6; + int kstat = 0; + int kcrv=0, kpt=0; + double *epar = 0; + SISLIntcurve **intcv = 0; + if (qc) + s1871(qc, &zero, 1, eps, &kpt, &epar, &kcrv, &intcv, &kstat); + if (qc) + freeCurve(qc); + if (kpt == 0) + return false; + + // Compute cartesian points and curves associated with intersections + double mindist = std::numeric_limits<double>::max(); + for (int kr=0; kr<kpt; ++kr) + { + Vector4D barypt = (1.0 - epar[kr])*bary1 + epar[kr]*bary2; + + Vector3D pos = bc_.baryToCart(barypt); + double dist = pos.dist(xyz); + if (dist < mindist) + { + mindist = dist; + proj[ka] = pos; + } + } + if (epar) free(epar); + if (intcv) freeIntcrvlist(intcv, kcrv); + + } + + projpos = Point(proj[0][0], proj[0][1], proj[0][2]); + Point pt2(proj[1][0], proj[1][1], proj[1][2]); + Point pt3(proj[2][0], proj[2][1], proj[2][2]); + + Point vec1 = pt2 - projpos; + Point vec2 = pt3 - projpos; + normal = vec1.cross(vec2); + normal.normalize_checked(); + return true; +} + +//=========================================================================== +void ImplicitApprox::visualize(vector<RevEngPoint*> points, std::ostream& os) +//=========================================================================== +{ + // View direction + Point dir = points[0]->getLocFuncNormal(); + dir.normalize(); + + BoundingBox bb(3); + for (size_t ki=0; ki<points.size(); ++ki) + { + Vector3D xyz = points[ki]->getPoint(); + bb.addUnionWith(Point(xyz[0], xyz[1], xyz[2])); + } + Point low = bb.low(); + Point high = bb.high(); + Point bmid = 0.5*(low + high); + Point diag = high - low; + double diaglen = diag.length(); + + double gap = 1.0e-6; + Point xdir(1.0, 0.0, 0.0); + Point ydir(0.0, 1.0, 0.0); + Point zdir(0.0, 0.0, 1.0); + CompositeModelFactory factory(gap, gap, 10.0*gap, 0.01, 0.05); + shared_ptr<SurfaceModel> boxmod(factory.createFromBox(low-2.0*diag, xdir, ydir, + 5*diag[0], 5*diag[1], 5*diag[2])); + + // Find the coordinate direction with the largest angle with the view direction + double a1 = xdir.angle(dir); + double a2 = ydir.angle(dir); + double a3 = zdir.angle(dir); + Point dir2; + if (a1 > std::min(a2, a3)) + dir2 = xdir; + else if (a2 > a3) + dir2 = ydir; + else + dir2 = zdir; + Point dir3 = dir%dir2; + dir2 = dir%dir3; + if (dir2*(high-low) < 0.0) + dir2 *= -1.0; + if (dir3*(high-low) < 0.0) + dir3 *= -1.0; + dir2.normalize(); + dir3.normalize(); + double len = low.dist(high); + int nmb_sample = 100; + shared_ptr<SplineCurve> cv1(new SplineCurve(bmid-len*dir2, 0.0, bmid+len*dir2, 1.0)); + shared_ptr<SplineCurve> cv2(new SplineCurve(bmid-len*dir3, 0.0, bmid+len*dir3, 1.0)); + SweepSurfaceCreator sweep; + shared_ptr<SplineSurface> ssf(sweep.linearSweptSurface(*cv1, *cv2, bmid)); + double del = 1.0/(double)(nmb_sample-1); + double p1, p2; + int ki, kj, kr; + int ik = degree_ + 1; + vector<double> et(2*ik, 0.0); // Knot vector of line curve + for (int ki=0; ki<ik; ++ki) + et[ik+ki] = 1.0; + + vector<double> sfpoints; + vector<double> vecs; + vector<double> linesegs; + vector<double> der; + vector<double> der2; + vector<double> lineder; + // Evaluate line + vector<double> tmpline; + for (kj=0, p2=0.0; kj<nmb_sample; ++kj, p2+=del) + { + for (ki=0, p1=0.0; ki<nmb_sample; ++ki, p1+=del) + { + // Compute barysentric coordinates of end points of line + // First cartesian + Point sfpos = ssf->ParamSurface::point(p1,p2); + Point cart1 = sfpos + len*dir; + Point cart2 = sfpos - len*dir; + tmpline.insert(tmpline.end(), cart1.begin(), cart1.end()); + tmpline.insert(tmpline.end(), cart2.begin(), cart2.end()); + + Vector4D bary1 = bc_.cartToBary(Vector3D(cart1[0], cart1[1], cart1[2])); + Vector4D bary2 = bc_.cartToBary(Vector3D(cart2[0], cart2[1], cart2[2])); + + Vector3D tp1 = bc_.baryToCart(bary1); + Vector3D tp2 = bc_.baryToCart(bary2); + + // Pick line + BernsteinPoly line = implicit_.pickLine(bary1, bary2); + + // Compute zeroes of bernstein polynomial + // First make sisl curve + vector<double> ecoef(line.coefsBegin(), line.coefsEnd()); + SISLCurve *qc = newCurve(ik, ik, &et[0], &ecoef[0], 1, 1, 1); + double zero = 0.0; + + // Intersect + double eps = 1.0e-6; + int kstat = 0; + int kcrv=0, kpt=0; + double *epar = 0; + SISLIntcurve **intcv = 0; + if (qc) + s1871(qc, &zero, 1, eps, &kpt, &epar, &kcrv, &intcv, &kstat); + if (qc) + freeCurve(qc); + + // Compute cartesian points and curves associated with intersections + for (kr=0; kr<kpt; ++kr) + { + Vector4D barypt = (1.0 - epar[kr])*bary1 + epar[kr]*bary2; + int kb; + for (kb=0; kb<4; ++kb) + if (barypt[kb] < -0.001 || barypt[kb] > 1.001) + break; + if (kb < 4) + continue; + + Vector3D pos = bc_.baryToCart(barypt); + sfpoints.insert(sfpoints.end(), pos.begin(), pos.end()); + + } + if (epar) free(epar); + if (intcv) freeIntcrvlist(intcv, kcrv); + } + } + + // Output + if (sfpoints.size() > 0) + { + PointCloud3D ptcloud(&sfpoints[0], sfpoints.size()/3); + os << "400 1 0 4 255 0 0 255" << std::endl; + ptcloud.write(os); + } +} + +//=========================================================================== +void ImplicitApprox::visualize(vector<Point> points, Point& dir, std::ostream& os) +//=========================================================================== +{ + BoundingBox bb(3); + for (size_t ki=0; ki<points.size(); ++ki) + { + bb.addUnionWith(points[ki]); + } + Point low = bb.low(); + Point high = bb.high(); + Point bmid = 0.5*(low + high); + Point diag = high - low; + double diaglen = diag.length(); + + double gap = 1.0e-6; + Point xdir(1.0, 0.0, 0.0); + Point ydir(0.0, 1.0, 0.0); + Point zdir(0.0, 0.0, 1.0); + CompositeModelFactory factory(gap, gap, 10.0*gap, 0.01, 0.05); + shared_ptr<SurfaceModel> boxmod(factory.createFromBox(low-2.0*diag, xdir, ydir, + 5*diag[0], 5*diag[1], 5*diag[2])); + + // Find the coordinate direction with the largest angle with the view direction + double a1 = xdir.angle(dir); + double a2 = ydir.angle(dir); + double a3 = zdir.angle(dir); + Point dir2; + if (a1 > std::min(a2, a3)) + dir2 = xdir; + else if (a2 > a3) + dir2 = ydir; + else + dir2 = zdir; + Point dir3 = dir%dir2; + dir2 = dir%dir3; + if (dir2*(high-low) < 0.0) + dir2 *= -1.0; + if (dir3*(high-low) < 0.0) + dir3 *= -1.0; + dir2.normalize(); + dir3.normalize(); + double len = low.dist(high); + int nmb_sample = 100; + shared_ptr<SplineCurve> cv1(new SplineCurve(bmid-len*dir2, 0.0, bmid+len*dir2, 1.0)); + shared_ptr<SplineCurve> cv2(new SplineCurve(bmid-len*dir3, 0.0, bmid+len*dir3, 1.0)); + SweepSurfaceCreator sweep; + shared_ptr<SplineSurface> ssf(sweep.linearSweptSurface(*cv1, *cv2, bmid)); + double del = 1.0/(double)(nmb_sample-1); + double p1, p2; + int ki, kj, kr; + int ik = degree_ + 1; + vector<double> et(2*ik, 0.0); // Knot vector of line curve + for (int ki=0; ki<ik; ++ki) + et[ik+ki] = 1.0; + + vector<double> sfpoints; + vector<double> vecs; + vector<double> linesegs; + vector<double> der; + vector<double> der2; + vector<double> lineder; + // Evaluate line + vector<double> tmpline; + for (kj=0, p2=0.0; kj<nmb_sample; ++kj, p2+=del) + { + for (ki=0, p1=0.0; ki<nmb_sample; ++ki, p1+=del) + { + // Compute barysentric coordinates of end points of line + // First cartesian + Point sfpos = ssf->ParamSurface::point(p1,p2); + Point cart1 = sfpos + len*dir; + Point cart2 = sfpos - len*dir; + tmpline.insert(tmpline.end(), cart1.begin(), cart1.end()); + tmpline.insert(tmpline.end(), cart2.begin(), cart2.end()); + + Vector4D bary1 = bc_.cartToBary(Vector3D(cart1[0], cart1[1], cart1[2])); + Vector4D bary2 = bc_.cartToBary(Vector3D(cart2[0], cart2[1], cart2[2])); + + Vector3D tp1 = bc_.baryToCart(bary1); + Vector3D tp2 = bc_.baryToCart(bary2); + + // Pick line + BernsteinPoly line = implicit_.pickLine(bary1, bary2); + + // Compute zeroes of bernstein polynomial + // First make sisl curve + vector<double> ecoef(line.coefsBegin(), line.coefsEnd()); + SISLCurve *qc = newCurve(ik, ik, &et[0], &ecoef[0], 1, 1, 1); + double zero = 0.0; + + // Intersect + double eps = 1.0e-6; + int kstat = 0; + int kcrv=0, kpt=0; + double *epar = 0; + SISLIntcurve **intcv = 0; + if (qc) + s1871(qc, &zero, 1, eps, &kpt, &epar, &kcrv, &intcv, &kstat); + if (qc) + freeCurve(qc); + + // Compute cartesian points and curves associated with intersections + for (kr=0; kr<kpt; ++kr) + { + Vector4D barypt = (1.0 - epar[kr])*bary1 + epar[kr]*bary2; + int kb; + for (kb=0; kb<4; ++kb) + if (barypt[kb] < -0.001 || barypt[kb] > 1.001) + break; + if (kb < 4) + continue; + + Vector3D pos = bc_.baryToCart(barypt); + sfpoints.insert(sfpoints.end(), pos.begin(), pos.end()); + + } + if (epar) free(epar); + if (intcv) freeIntcrvlist(intcv, kcrv); + } + } + + // Output + if (sfpoints.size() > 0) + { + PointCloud3D ptcloud(&sfpoints[0], sfpoints.size()/3); + os << "400 1 0 4 255 0 0 255" << std::endl; + ptcloud.write(os); + } +} + + +double fc(int deg, int power[], double coef[], double x, double y, double z) +{ + int nn = (deg+1)*(deg+2)*(deg+3)/6; + double res = 0.0; + for (int ki=0; ki<nn; ++ki) + { + double tmp1 = 1; + for (int kj=0; kj<power[4*ki]; ++kj) + tmp1 *= x; + double tmp2 = 1; + for (int kj=0; kj<power[4*ki+1]; ++kj) + tmp2 *= y; + double tmp3 = 1; + for (int kj=0; kj<power[4*ki+2]; ++kj) + tmp3 *= z; + res += (coef[ki]*tmp1*tmp2*tmp3); + } + return res; +} + +double f(int deg, int power[], int ki, double x, double y, double z) +{ + double tmp1 = 1; + for (int kj=0; kj<power[4*ki]; ++kj) + tmp1 *= x; + double tmp2 = 1; + for (int kj=0; kj<power[4*ki+1]; ++kj) + tmp2 *= y; + double tmp3 = 1; + for (int kj=0; kj<power[4*ki+2]; ++kj) + tmp3 *= z; + double res = tmp1*tmp2*tmp3; + return res; +} + +double fx(int deg, int power[], int ki, double x, double y, double z) +{ + double res = 0.0; + if (power[4*ki] > 0) + { + double tmp = (double)power[4*ki]; + for (int kj=0; kj<power[4*ki]-1; ++kj) + tmp *= x; + for (int kj=0; kj<power[4*ki+1]; ++kj) + tmp *= y; + for (int kj=0; kj<power[4*ki+2]; ++kj) + tmp *= z; + res = tmp; + } + + return res; +} + +double fy(int deg, int power[], int ki, double x, double y, double z) +{ + double res = 0.0; + if (power[4*ki+1] > 0) + { + double tmp = (double)power[4*ki+1]; + for (int kj=0; kj<power[4*ki+1]-1; ++kj) + tmp *= y; + for (int kj=0; kj<power[4*ki]; ++kj) + tmp *= x; + for (int kj=0; kj<power[4*ki+2]; ++kj) + tmp *= z; + res = tmp; + } + return res; +} + +double fz(int deg, int power[], int ki, double x, double y, double z) +{ + double res = 0.0; + if (power[4*ki+2] > 0) + { + double tmp = (double)power[4*ki+2]; + for (int kj=0; kj<power[4*ki+2]-1; ++kj) + tmp *= z; + for (int kj=0; kj<power[4*ki]; ++kj) + tmp *= x; + for (int kj=0; kj<power[4*ki+1]; ++kj) + tmp *= y; + res = tmp; + } + return res; +} + + +//=========================================================================== +void ImplicitApprox::polynomialSurf(vector<Point>& pos_and_der, int degree, + vector<double>& coefs) +//=========================================================================== +{ + // Assemble matrix + int nmbvar = (degree+1)*(degree+2)*(degree+3)/6; + size_t nmb_pts = pos_and_der.size()/3; + vector<vector<double> > M(nmb_pts); + vector<vector<double> > N1(nmb_pts); + vector<vector<double> > N2(nmb_pts); + for (size_t kr=0; kr<nmb_pts; ++kr) + { + M[kr].resize(nmbvar, 0.0); + N1[kr].resize(nmbvar, 0.0); + N2[kr].resize(nmbvar, 0.0); + } + + vector<int> power(4*nmbvar); + for (int ki=0, kr=0; ki<=degree; ++ki) + for (int kj=0; kj<=degree-ki; ++kj) + for (int kh=0; kh<=degree-ki-kj; ++kh, kr+=4) + { + power[kr] = ki; + power[kr+1] = kj; + power[kr+2] = kh; + power[kr+3] = degree-ki-kj-kh; + } + + for (size_t kr=0, kh=0; kr<pos_and_der.size(); kr+=3, ++kh) + { + for (int ki=0; ki<nmbvar; ++ki) + { + double m1 = f(degree, &power[0], ki, pos_and_der[kr][0], + pos_and_der[kr][1], pos_and_der[kr][2]); + Point tmp1(3); + tmp1[0] = fx(degree, &power[0], ki, pos_and_der[kr][0], + pos_and_der[kr][1], pos_and_der[kr][2]); + tmp1[1] = fy(degree, &power[0], ki, pos_and_der[kr][0], + pos_and_der[kr][1], pos_and_der[kr][2]); + tmp1[2] = fz(degree, &power[0], ki, pos_and_der[kr][0], + pos_and_der[kr][1], pos_and_der[kr][2]); + double n1 = tmp1*pos_and_der[kr+1]; + double n2 = tmp1*pos_and_der[kr+2]; + M[kh][ki] += m1; + N1[kh][ki] += n1; + N2[kh][ki] += n2; + } + } + + + double lambda = 0.2; + NEWMAT::Matrix mat; + mat.ReSize(nmb_pts,nmbvar); + for (int ki=0; ki<nmb_pts; ++ki) + for (int kj=0; kj<nmbvar; ++kj) + mat.element(ki,kj) = M[ki][kj] + lambda*(N1[ki][kj] + N2[ki][kj]); + + static NEWMAT::DiagonalMatrix diag; + static NEWMAT::Matrix V; + try { + NEWMAT::SVD(mat, diag, mat, V); + } catch(...) { + std::cout << "Exception in SVD" << std::endl; + return; + } + + int write_info = 1; + if (write_info) + { + std::cout << "Singular values:" << std::endl; + for (int ki = 0; ki < nmbvar; ++ki) + std::cout << ki << "\t" << diag.element(ki, ki) << std::endl; + + // Write out info about singular values + double s_min = diag.element(nmbvar-1,nmbvar-1); + double s_max = diag.element(0, 0); + std::cout << "Implicitization:" << std::endl + << "s_min = " << s_min << std::endl + << "s_max = " << s_max << std::endl + << "Ratio of s_min/s_max = " << s_min/s_max << std::endl; + std::cout << "Ratio s_min/s_next_min = " << diag.element(nmbvar-1,nmbvar-1)/diag.element(nmbvar-2,nmbvar-2) << std::endl; + } + + coefs.resize(nmbvar); + for (int ki=0; ki<nmbvar; ++ki) + coefs[ki] = V.element(ki, nmbvar-1); + +} + +//=========================================================================== +void ImplicitApprox::polynomialSurfAccuracy(vector<Point>& pos_and_der, + int degree, vector<double>& coefs, + double& maxfield, double& avfield, + double& maxdist, double& avdist, + int& ndiv, double& maxang, + double& avang) +//=========================================================================== +{ + int nmbvar = (degree+1)*(degree+2)*(degree+3)/6; + size_t nmb_pts = pos_and_der.size()/3; + double eps = 1.0e-10; + double min_grad = 1.0e-9; + + vector<int> power(4*nmbvar); + for (int ki=0, kr=0; ki<=degree; ++ki) + for (int kj=0; kj<=degree-ki; ++kj) + for (int kh=0; kh<=degree-ki-kj; ++kh, kr+=4) + { + power[kr] = ki; + power[kr+1] = kj; + power[kr+2] = kh; + power[kr+3] = degree-ki-kj-kh; + } + + // Test accuracy + maxfield = 0.0; + avfield = 0.0; + double avgradlen = 0.0; + double mingradlen = 1.0e8; + double maxgradlen = 0.0; + double minang = 1.0e8; + maxang = 0.0; + avang = 0.0; + double mindist = 1.0e8; + maxdist = 0.0; + avdist = 0.0; + vector<Point> out; + ndiv = 0; + for (size_t kr=0; kr<nmb_pts; kr+=3) + { + double field = 0.0; + double dx=0.0, dy=0.0, dz=0.0; + for (int ki=0; ki<nmbvar; ++ki) + { + field += coefs[ki]*f(degree, &power[0], ki, pos_and_der[kr][0], + pos_and_der[kr][1], pos_and_der[kr][2]); + dx += coefs[ki]*fx(degree, &power[0], ki, pos_and_der[kr][0], + pos_and_der[kr][1], pos_and_der[kr][2]); + dy += coefs[ki]*fy(degree, &power[0], ki, pos_and_der[kr][0], + pos_and_der[kr][1], pos_and_der[kr][2]); + dz += coefs[ki]*fz(degree, &power[0], ki, pos_and_der[kr][0], + pos_and_der[kr][1], pos_and_der[kr][2]); + } + Point grad(dx, dy, dz); + Point normc = pos_and_der[kr+1].cross(pos_and_der[kr+2]); + double ang = normc.angle(grad); + minang = std::min(minang, ang); + maxang = std::max(maxang, ang); + avang += ang; + double gradlen = grad.length(); + double edist = (gradlen < 1.0e-17) ? 0.0 : fabs(field)/gradlen; + maxfield = std::max(maxfield, fabs(field)); + avfield += fabs(field); + mingradlen = std::min(mingradlen, gradlen); + maxgradlen = std::max(maxgradlen, gradlen); + avgradlen += gradlen; + if (gradlen > 1.0e-10) + grad.normalize(); + + double delta = 1.0e-9; + Point norm = grad; //tan1[kr].cross(tan2[kr]); + norm.normalize(); + double t0 = 0.0; + Point pos0 = pos_and_der[kr]; + double dt = dx*norm[0] + dy*norm[1] + dz*norm[2]; + double tdel = -field/dt; + double field0; + for (int ka=0; ka<10; ++ka) + { + if (fabs(tdel) < delta) + break; + t0 += tdel; + pos0 = pos_and_der[kr] + t0*norm; + double dx0 = 0.0, dy0 = 0.0, dz0 = 0.0; + field0 = 0.0; + for (int ki=0; ki<nmbvar; ++ki) + { + field0 += coefs[ki]*f(degree, &power[0], ki, pos0[0],pos0[1],pos0[2]); + dx0 += coefs[ki]*fx(degree, &power[0], ki, pos0[0],pos0[1],pos0[2]); + dy0 += coefs[ki]*fy(degree, &power[0], ki, pos0[0],pos0[1],pos0[2]); + dz0 += coefs[ki]*fz(degree, &power[0], ki, pos0[0],pos0[1],pos0[2]); + } + dt = dx0*norm[0] + dy0*norm[1] + dz0*norm[2]; + tdel = -field0/dt; + int stop_break = 1; + } + + if (fabs(field0) > fabs(field) || fabs(field0) > eps || fabs(t0) > 1.0 || + gradlen < min_grad) + { + out.push_back(pos_and_der[kr]); + ndiv++; + } + else + { + maxdist = std::max(maxdist, fabs(t0)); + mindist = std::min(mindist, fabs(t0)); + avdist += fabs(t0); + } + } + avfield /= (double)nmb_pts; + avang /= (double)nmb_pts; + avgradlen /= (double)nmb_pts; + avdist /= (double)(nmb_pts-ndiv); + + std::cout << "Maximum field: " << maxfield << std::endl; + std::cout << "Average field: " << avfield << std::endl; + std::cout << "Minimum distance: " << mindist << std::endl; + std::cout << "Maximum distance: " << maxdist << std::endl; + std::cout << "Average distance: " << avdist << std::endl; + std::cout << "Num divergent: " << ndiv << std::endl; + std::cout << "Minimum angle difference: " << minang << std::endl; + std::cout << "Maximum angle difference: " << maxang << std::endl; + std::cout << "Avarage angle difference: " << avang << std::endl; + std::cout << "Minimum gradient length: " << mingradlen << std::endl; + std::cout << "Maximum gradient length: " << maxgradlen << std::endl; + std::cout << "Average gradient length: " << avgradlen << std::endl; + + std::ofstream ofo("out.g2"); + ofo << "400 1 0 4 50 50 155 255" << std::endl; + ofo << out.size() << std::endl; + for (int ka=0; ka<(int)out.size(); ++ka) + ofo << out[ka] << std::endl; + + int stop_break = 1; + +} diff --git a/compositemodel/src/RevEng.C b/compositemodel/src/RevEng.C new file mode 100644 index 00000000..f086ebaf --- /dev/null +++ b/compositemodel/src/RevEng.C @@ -0,0 +1,14427 @@ +/* + * Copyright (C) 1998, 2000-2007, 2010, 2011, 2012, 2013 SINTEF ICT, + * Applied Mathematics, Norway. + * + * Contact information: E-mail: tor.dokken@sintef.no + * SINTEF ICT, Department of Applied Mathematics, + * P.O. Box 124 Blindern, + * 0314 Oslo, Norway. + * + * This file is part of GoTools. + * + * GoTools is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * GoTools 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with GoTools. If not, see + * <http://www.gnu.org/licenses/>. + * + * In accordance with Section 7(b) of the GNU Affero General Public + * License, a covered work must retain the producer line in every data + * file that is created or manipulated using GoTools. + * + * Other Usage + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial activities involving the GoTools library without + * disclosing the source code of your own applications. + * + * This file may be used in accordance with the terms contained in a + * written agreement between you and SINTEF ICT. + */ + +#include "GoTools/compositemodel/RevEng.h" +#include "GoTools/compositemodel/RevEngPoint.h" +#include "GoTools/compositemodel/RevEngEdge.h" +//#include "GoTools/compositemodel/RevEngRegion.h" +#include "GoTools/compositemodel/RevEngUtils.h" +#include "GoTools/compositemodel/HedgeSurface.h" +#include "GoTools/compositemodel/ImplicitApprox.h" +#include "GoTools/compositemodel/SurfaceModelUtils.h" +#include "GoTools/utils/DirectionCone.h" +#include "GoTools/utils/MatrixXD.h" +#include "GoTools/creators/CurveCreators.h" +#include "GoTools/creators/CreatorsUtils.h" +#include "GoTools/creators/CoonsPatchGen.h" +#include "GoTools/geometry/Cylinder.h" +#include "GoTools/geometry/Cone.h" +#include "GoTools/geometry/Plane.h" +#include "GoTools/geometry/Torus.h" +#include "GoTools/geometry/Sphere.h" +#include "GoTools/geometry/BoundedSurface.h" +#include "GoTools/geometry/BoundedUtils.h" +#include "GoTools/geometry/ClosestPoint.h" +#include "GoTools/geometry/SurfaceTools.h" +#include "GoTools/geometry/SISLconversion.h" +#include "GoTools/geometry/SplineDebugUtils.h" +#include "sislP.h" +#include <vector> +#include <set> +#include <fstream> +#include <iostream> // @@ debug + +using namespace Go; +using std::vector; +using std::pair; +using std::istream; +using std::ostream; + +typedef MatrixXD<double, 3> Matrix3D; + +#define MAX_COLORS 12 +int colors[MAX_COLORS][3] = { + {255, 0, 0}, + {0, 255, 0}, + {0, 0, 255}, + {255, 255, 0}, + {255, 0, 255}, + {0, 255, 255}, + {128, 255, 0}, + {255, 128, 0}, + {128, 0, 255}, + {255, 0, 128}, + {0, 128, 255}, + {0, 255, 128}, +}; + +//#define DEBUG_DIV +//#define DEBUG_EDGE0 +//#define DEBUG_BLEND +//#define DEBUG_MONGE +//#define DEBUG_ENHANCE +//#define DEBUG_SEG +//#define DEBUG +//#define DEBUGONE +//#define DEBUG_CHECK +//#define DEBUG_PLANAR +//#define DEBUG_AXIS +//#define DEBUG_GROW +//#define DEBUG_VALIDATE +//#define DEBUG_EDGE +//#define DEBUG_TRIANG +//#define DEBUG_TRIM +//#define DEBUG_MODEL +//#define DEBUG_SMALL + +//=========================================================================== +RevEng::RevEng(shared_ptr<ftPointSet> tri_sf) + : tri_sf_(tri_sf) +//=========================================================================== +{ + mean_edge_len_ = 0.0; + int num = tri_sf_->size(); + if (num > 0.0) + { + double fac1 = 1.0/(double)num; + for (int ki=0; ki<num; ++ki) + { + double tmp_len = 0.0; + ftSamplePoint* curr = (*tri_sf_)[ki]; + Vector3D xyz1 = curr->getPoint(); + vector<ftSamplePoint*> adj = curr->getNeighbours(); + if (adj.size() > 0) + { + double fac2 = 1.0/(double)adj.size(); + for (size_t kj=0; kj<adj.size(); ++kj) + { + Vector3D xyz2 = adj[kj]->getPoint(); + tmp_len += fac2*xyz1.dist(xyz2); + } + } + mean_edge_len_ += fac1*tmp_len; + } + } + + + + // Set default parameters + model_character_ = ROUGH; + initParameters(); + max_next_ = std::min(80, tri_sf_->size()/200); + max_next_ = std::max(2*min_next_, max_next_); +} + + +//=========================================================================== +RevEng::RevEng() +//=========================================================================== +{ + // Empty infrastructure for reading stage + model_character_ = ROUGH; + initParameters(); +} + + +//=========================================================================== +RevEng::~RevEng() +//=========================================================================== +{ +} + + +int compare_x_par(const RevEngPoint* p1, const RevEngPoint* p2) +{ + return (p1->getPoint()[0] < p2->getPoint()[0]); + // if (p1->getPoint()[0] < p2->getPoint()[0]) + // return -1; + // else if (p1->getPoint()[0] > p2->getPoint()[0]) + // return 1; + // else + // return 0; +} + +int compare_y_par(const RevEngPoint* p1, const RevEngPoint* p2) +{ + return (p1->getPoint()[1] < p2->getPoint()[1]); + // if (p1->getPoint()[1] < p2->getPoint()[1]) + // return -1; + // else if (p1->getPoint()[1] > p2->getPoint()[1]) + // return 1; + // else + // return 0; +} + +int compare_z_par(const RevEngPoint* p1, const RevEngPoint* p2) +{ + return (p1->getPoint()[2] < p2->getPoint()[2]); + // if (p1->getPoint()[2] < p2->getPoint()[2]) + // return -1; + // else if (p1->getPoint()[2] > p2->getPoint()[2]) + // return 1; + // else + // return 0; +} + +//=========================================================================== +void RevEng::setBoundingBox() +//=========================================================================== +{ + int nmbpt = tri_sf_->size(); + vector<RevEngPoint*> all_pts(nmbpt); + for (int ki=0; ki<nmbpt; ++ki) + { + RevEngPoint* pt = dynamic_cast<RevEngPoint*>((*tri_sf_)[ki]); + Vector3D xyz = pt->getPoint(); + Point xyz2 = Point(xyz[0], xyz[1], xyz[2]); + all_pts[ki] = pt; + if (ki == 0) + bbox_ = BoundingBox(xyz2, xyz2); + else + bbox_.addUnionWith(xyz2); + } + +} + +//=========================================================================== +void RevEng::enhancePoints() +//=========================================================================== +{ + setBoundingBox(); +#ifdef DEBUG_ENHANCE + std::cout << "Bounding box, min: " << bbox_.low() << ", max: " << bbox_.high() << std::endl; +#endif + + // Update parameters based on surface roughness + updateParameters(); + int nmbpt = tri_sf_->size(); + +#ifdef DEBUG_TRIANG + vector<vector<RevEngPoint*> > conn_groups; + for (int ki=0; ki<nmbpt; ++ki) + { + RevEngPoint *pt = dynamic_cast<RevEngPoint*>((*tri_sf_)[ki]); + if (pt->visited()) + continue; + vector<RevEngPoint*> curr_group; + pt->fetchConnected(0, nmbpt, curr_group); + conn_groups.push_back(curr_group); + } + + for (int ki=0; ki<nmbpt; ++ki) + { + RevEngPoint *pt = dynamic_cast<RevEngPoint*>((*tri_sf_)[ki]); + pt->unsetVisited(); + } + + std::ofstream oftri("init_ptgroups.g2"); + for (size_t kj=0; kj<conn_groups.size(); ++kj) + { + oftri << "400 1 0 0" << std::endl; + oftri << conn_groups[kj].size() << std::endl; + for (size_t kr=0; kr<conn_groups[kj].size(); ++kr) + oftri << conn_groups[kj][kr]->getPoint() << std::endl; + } +#endif + +#ifdef DEBUG_DIV + int writepoints = 0; + vector<double> tri_ang(nmbpt); +#endif + for (int ki=0; ki<nmbpt; ++ki) + { + RevEngPoint *pt = dynamic_cast<RevEngPoint*>((*tri_sf_)[ki]); + + // Compute surface normal from triangulation + pt->computeTriangNormal(100.0*mean_edge_len_); + if (pt->getNmbNeighbour() == 0) + pt->setOutlier(); + //double avlen = pt->getMeanEdgLen(); +#ifdef DEBUG_DIV + tri_ang[ki] = pt->getTriangAngle(); +#endif + } +#ifdef DEBUG_ENHANCE + std::sort(tri_ang.begin(), tri_ang.end()); + std::cout << "Triangle angles: " << tri_ang[0] << " " << tri_ang[nmbpt/4]; + std::cout << " " << tri_ang[nmbpt/2] << " " << tri_ang[3*nmbpt/4]; + std::cout << " " << tri_ang[nmbpt-1] << std::endl; + std::cout << "norm_ang_lim_ : " << norm_ang_lim_ << std::endl; +#endif + + double wgt_nmb = 1.0/(double)nmbpt; + double av_close = 0.0; + int max_close = 0; + int min_close = nmbpt; + vector<double> lambda_3(nmbpt); + for (int ki=0; ki<nmbpt; ++ki) + { + RevEngPoint *pt = dynamic_cast<RevEngPoint*>((*tri_sf_)[ki]); + if (pt->nmbLocFunc() > 0) + continue; // Already enhanced + + // // Compute surface normal from triangulation + // pt->computeTriangNormal(100.0*mean_edge_len_); + if (pt->isOutlier()) + continue; + + // if (pt->getNmbNeighbour() == 0) + // { + // pt->setOutlier(); + // continue; + // } + + //double avlen = pt->getMeanEdgLen(); + + //Fetch nearby points + vector<RevEngPoint*> nearpts; + double local_len = pt->getMeanEdgLen(10.0*mean_edge_len_); + double radius = rfac_*(local_len + mean_edge_len_); + double radius2 = 0.5*radius; + radius = std::min(radius, 20.0*mean_edge_len_); + //radius *= 1.5; // TEST + //double radius = 0.5*rfac_*(local_len + mean_edge_len_); + pt->fetchClosePoints2(radius, min_next_, max_next_, nearpts); + + Point mincvec(0.0, 0.0, 0.0), maxcvec(0.0, 0.0, 0.0); + // Point mincvec2(0.0, 0.0, 0.0), maxcvec2(0.0, 0.0, 0.0); + + av_close += wgt_nmb*(double)nearpts.size(); + max_close = std::max(max_close, (int)nearpts.size()); + min_close = std::min(min_close, (int)nearpts.size()); + + if (nearpts.size() >= 3) + { +#ifdef DEBUG_DIV + std::ofstream of("nearpts.g2"); + if (writepoints) + { + of << "400 1 0 4 255 0 0 255" << std::endl; + of << "1" << std::endl; + of << pt->getPoint() << std::endl << std::endl; + of << "400 1 0 4 0 255 0 255" << std::endl; + of << nearpts.size() << std::endl; + for (size_t kr=0; kr<nearpts.size(); ++kr) + of << nearpts[kr]->getPoint() << std::endl; + } +#endif + + // Compute eigenvectors and values of covariance matrix + nearpts.push_back(pt); + double lambda[3]; + double eigenvec[3][3]; + RevEngUtils::principalAnalysis(nearpts, lambda, eigenvec); + Point eigen1(eigenvec[0][0], eigenvec[0][1], eigenvec[0][2]); + Point eigen2(eigenvec[1][0], eigenvec[1][1], eigenvec[1][2]); + Point eigen3(eigenvec[2][0], eigenvec[2][1], eigenvec[2][2]); + lambda_3[ki] = lambda[2]; + Point tnorm = pt->getTriangNormal(); + if (tnorm.length() < 1.0e-10) + { + int stop_norm = 1; + } + else if (eigen3*tnorm < 0.0) + { + eigen2 *= -1; + eigen3 *= -1; + } + + for (size_t kr=0; kr<nearpts.size(); ++kr) + { + if (pt->pntDist(nearpts[kr]) <= radius2) + nearpts[kr]->addCovarianceEigen(eigen1, lambda[0], eigen2, lambda[1], + eigen3, lambda[2]); + } +#ifdef DEBUG_DIV + if (writepoints) + { + for (int ki=0; ki<3; ++ki) + { + Vector3D vec(eigenvec[ki][0], eigenvec[ki][1], eigenvec[ki][2]); + of << "410 1 0 4 0 0 0 255" << std::endl; + of << "1" << std::endl; + Vector3D curr = pt->getPoint(); + of << curr << " " << curr+0.1*vec << std::endl; + } + } +#endif + // Compute normal and curvature using LocFunc patch + // Point normal;//, mincvec, maxcvec; + // double minc, maxc; + // double currdist, avdist; + // RevEngUtils::computeLocFunc(curr, nearpts, eigen1, eigen3, normal, mincvec, minc, + // maxcvec, maxc, currdist, avdist); + computeLocFunc(pt, nearpts, eigen1, eigen3, radius2); + // Orient vectors with respect to triangulation normal + // The normal vectors should be OK. Curvature vectors are not necessarily + // consistent with regard to orientation + + int stop_break = 1; + } + } + +#ifdef DEBUG + vector<Vector3D> pts1; + vector<Vector3D> lin1; + for (int ki=0; ki<nmbpt; ++ki) + { + RevEngPoint *pt = dynamic_cast<RevEngPoint*>((*tri_sf_)[ki]); + if (!pt->isOutlier()) + { + pts1.push_back(pt->getPoint()); + vector<ftSamplePoint*> next = pt->getNeighbours(); + for (size_t kj=0; kj<next.size(); ++kj) + { + RevEngPoint *pt2 = dynamic_cast<RevEngPoint*>(next[kj]); + if (!pt2->isOutlier()) + { + lin1.push_back(pt->getPoint()); + lin1.push_back(pt2->getPoint()); + } + } + } + } + std::ofstream ofout1("not_outliers.g2"); + ofout1 << "400 1 0 4 0 0 0 255" << std::endl; + ofout1 << pts1.size() << std::endl; + for (size_t kj=0; kj<pts1.size(); ++kj) + ofout1 << pts1[kj] << std::endl; + ofout1 << "410 1 0 4 55 100 100 255" << std::endl; + ofout1 << lin1.size()/2 << std::endl; + for (size_t kj=0; kj<lin1.size(); kj+=2) + ofout1 << lin1[kj] << " " << lin1[kj+1] << std::endl; +#endif + std::sort(lambda_3.begin(), lambda_3.end()); +#ifdef DEBUG_ENHANCE + std::cout << "No close, min: " << min_close << ", max: " << max_close << ", average: " << av_close << std::endl; + std::cout << "lambda3, min: " << lambda_3[0] << ", max: " << lambda_3[nmbpt-1] << ", medium: " << lambda_3[nmbpt/2] << std::endl; +#endif + + + for (int ki=0; ki<nmbpt; ++ki) + { + // Check orientation of curvature + RevEngPoint *pt = dynamic_cast<RevEngPoint*>((*tri_sf_)[ki]); + if (pt->isOutlier()) + continue; + Point tnorm = pt->getTriangNormal(); + if (tnorm.length() < 1.0e-10) + { + // Fetch triangulation normal in neighbour + vector<ftSamplePoint*> next = pt->getNeighbours(); + double mindist = std::numeric_limits<double>::max(); + int ix = -1; + for (size_t kr=0; kr<next.size(); ++kr) + { + double dist = pt->pntDist(next[kr]); + RevEngPoint *nextpt = dynamic_cast<RevEngPoint*>(next[kr]); + Point nextnorm = nextpt->getTriangNormal(); + if (dist < mindist && nextnorm.length() > 1.0e-10) + { + mindist = dist; + ix = (int)kr; + } + } + if (ix >= 0) + { + RevEngPoint *nextpt = dynamic_cast<RevEngPoint*>(next[ix]); + tnorm = nextpt->getTriangNormal(); + Point PCAnorm = pt->getPCANormal(); + if (tnorm*PCAnorm < 0.0) + pt->turnPCA(); + Point LocFuncnorm = pt->getLocFuncNormal(); + if (tnorm*LocFuncnorm < 0.0) + pt->turnLocFuncNorm(); + } + + } + } + + +#ifdef DEBUG_ENHANCE + std::cout << "Start curvature filter" << std::endl; +#endif + curvatureFilter(); + +#ifdef DEBUG_ENHANCE + std::cout << "Finish curvature filter" << std::endl; +#endif + int stop_break = 1; + +} + +//=========================================================================== +void RevEng::computeLocFunc(RevEngPoint* pt, std::vector<RevEngPoint*>& points, + Point& vec1, Point& vec2, double radius) +//=========================================================================== +{ + // Transform points to coordinate system given by vec1 (x-axis) and vec2 (y-axis) + Matrix3D mat1, mat2, rotmat; + Vector3D vec1_2(vec1[0], vec1[1], vec1[2]); + Vector3D vec2_2(vec2[0], vec2[1], vec2[2]); + Vector3D xaxis(1, 0, 0); + Vector3D zaxis(0, 0, 1); + mat1.setToRotation(vec1_2, xaxis); + Vector3D v1 = mat1*vec1_2; + Vector3D vec2_3 = mat1*vec2_2; + mat2.setToRotation(vec2_3, zaxis); + Vector3D v2 = mat2*vec2_3; + rotmat = mat2*mat1; + //rotmat.identity(); + + // Perform rotation and sort parameter values and z-value + int nmbpts = (int)points.size(); + vector<double> par(2*nmbpts); + vector<double> zval(nmbpts); + Vector3D curr = pt->getPoint(); + for (int ki=0; ki<nmbpts; ++ki) + { + Vector3D dv = points[ki]->getPoint() - curr; + Vector3D dvrot = rotmat*dv; + //Vector3D dvrot = mat2*dvrot0; + par[2*ki] = curr[0] + dvrot[0]; + par[2*ki+1] = curr[1] + dvrot[1]; + zval[ki] = curr[2] + dvrot[2]; + } + + // Approximate z-component by biquadratic Bezier function in x and y + int order = 3; + shared_ptr<SplineSurface> mongesf = RevEngUtils::surfApprox(zval, 1, par, order, + order, order, order); + + vector<double> coefs2(3*order*order); + std::vector<double>::iterator cf = mongesf->coefs_begin(); + for (int ka=0; ka<order; ++ka) + { + double vpar = mongesf->basis_v().grevilleParameter(ka); + for (int kb=0; kb<order; ++kb, ++cf) + { + double upar = mongesf->basis_u().grevilleParameter(kb); + coefs2[(ka*order+kb)*3] = upar; + coefs2[(ka*order+kb)*3+1] = vpar; + coefs2[(ka*order+kb)*3+2] = *cf; + } + } + shared_ptr<SplineSurface> tmp(new SplineSurface(order, order, order, order, + mongesf->basis_u().begin(), + mongesf->basis_v().begin(), &coefs2[0], 3)); +#ifdef DEBUG_DIV + int writesurface = 0; + if (writesurface) + { + std::ofstream of("approx_sf.g2"); + tmp->writeStandardHeader(of); + tmp->write(of); + of << "400 1 0 4 0 255 0 255" << std::endl; + of << 1 << std::endl; + of << curr << std::endl; + of << "400 1 0 4 255 0 0 255" << std::endl; + of << nmbpts << std::endl; + for (int ka=0; ka<nmbpts; ++ka) + { + Point tmppt(par[2*ka], par[2*ka+1], zval[ka]); + of << tmppt << std::endl; + } + } +#endif + + // Compute surface normal + double avdist = 0.0; + for (int ki=0; ki<nmbpts; ++ki) + { + Point pos; + mongesf->point(pos, par[2*ki], par[2*ki+1]); + avdist += fabs(zval[ki] - pos[0]); + } + avdist /= (double)nmbpts; + +#ifdef DEBUG_MONGE + std::ofstream of2("LocFunc_curvature.g2"); + std::ofstream of3("LocFunc_curvature2.g2"); +#endif + vector<Point> monge1, monge2, monge3, monge4; + for (size_t kr=0; kr<points.size(); ++kr) + { + if (pt->pntDist(points[kr]) > radius) + continue; + + Point triang_norm = points[kr]->getTriangNormal(); + vector<Point> der(3); + mongesf->point(der, par[2*kr], par[2*kr+1], 1); + Vector3D norm(-der[1][0], -der[2][0], 1.0); + norm.normalize(); + + // Accuracy of approximation + double currdist = fabs(zval[kr] - der[0][0]); + + // Compute principal curvatures in curr + SISLSurf *sislsf = GoSurf2SISL(*mongesf, false); + int left1 = 0, left2 = 0; + int stat = 0; + double minc, maxc; + double d1[2], d2[2]; + s2542(sislsf, 0, 0, 0, &par[0], &left1, &left2, &minc, &maxc, d1, d2, &stat); + Vector3D du(1.0, 0.0, der[1][0]); + Vector3D dv(0.0, 1.0, der[2][0]); + Vector3D cvec1 = d1[0]*du + d1[1]*dv; + Vector3D cvec2 = d2[0]*du + d2[1]*dv; + if (sislsf) freeSurf(sislsf); + + // Vector3D origin(par[0], par[1], zval[0]); + // of << "410 1 0 4 0 0 0 255" << std::endl; + // of << "1" << std::endl; + // of << origin << " " << origin+norm << std::endl; + + // of << "410 1 0 4 0 55 155 255" << std::endl; + // of << "1" << std::endl; + // of << origin << " " << origin+cvec1 << std::endl; + + + // of << "410 1 0 4 155 55 0 255" << std::endl; + // of << "1" << std::endl; + // of << origin << " " << origin+cvec2 << std::endl; + + + + // Transform results to original coordinate system + Matrix3D mat3, mat4, rotmat2; + mat4.setToRotation(zaxis, vec2_3); + mat3.setToRotation(xaxis, vec1_2); + rotmat2 = mat3*mat4; + //rotmat2.identity(); + //Vector3D norm0 = mat4*norm; + Vector3D norm2 = rotmat2*norm; + Point normal = Point(norm2[0], norm2[1], norm2[2]); + if (triang_norm.length() > 1.0e-10 && normal*triang_norm < 0.0) + normal *= -1; + + Vector3D cvec3 = rotmat2*cvec1; + Point mincvec = Point(cvec3[0], cvec3[1], cvec3[2]); + Vector3D cvec4 = rotmat2*cvec2; + Point maxcvec = Point(cvec4[0], cvec4[1], cvec4[2]); + points[kr]->addLocFuncInfo(normal, mincvec, minc, maxcvec, maxc, currdist, avdist); + + // Vector3D xyz = points[kr]->getPoint(); + // Point xyz2 = Point(xyz[0], xyz[1], xyz[2]); + // Vector3D der2(der[0][0], der[0][1], der[0][2]); + // Vector3D der3 = rotmat2*der2; + // Point der4(der3[0], der3[1], der3[2]); // Not a 3D point!!! + // monge1.push_back(xyz2); + // monge1.push_back(xyz2+mincvec); + // monge2.push_back(xyz2); + // monge2.push_back(xyz2+maxcvec); + // monge3.push_back(der4); + // monge3.push_back(der4+mincvec); + // monge4.push_back(der4); + // monge4.push_back(der4+maxcvec); + } + + // int writeLocFunc = 0; + + // if (writeLocFunc) + // { + // of2 << "410 1 0 4 255 0 0 255" << std::endl; + // of2 << monge1.size()/2 << std::endl; + // for (size_t kr=0; kr<monge1.size(); kr+=2) + // of2 << monge1[kr] << " " << monge1[kr+1] << std::endl; + // of2 << "410 1 0 4 0 0 255 255" << std::endl; + // of2 << monge2.size()/2 << std::endl; + // for (size_t kr=0; kr<monge2.size(); kr+=2) + // of2 << monge2[kr] << " " << monge2[kr+1] << std::endl; + + // of3 << "400 1 0 4 0 255 0 255" << std::endl; + // of3 << monge3.size()/2 << std::endl; + // for (size_t kr=0; kr<monge3.size(); kr+=2) + // of3 << monge3[kr] << std::endl; + // of3 << "410 1 0 4 255 0 0 255" << std::endl; + // of3 << monge3.size()/2 << std::endl; + // for (size_t kr=0; kr<monge3.size(); kr+=2) + // of3 << monge3[kr] << " " << monge3[kr+1] << std::endl; + // of3 << "410 1 0 4 0 0 255 255" << std::endl; + // of3 << monge4.size()/2 << std::endl; + // for (size_t kr=0; kr<monge4.size(); kr+=2) + // of3 << monge4[kr] << " " << monge4[kr+1] << std::endl; + // } + int stop_break = 1; +} + + +//=========================================================================== +void RevEng::curvatureFilter() +//=========================================================================== +{ + int nmbpt = tri_sf_->size(); + double radius_fac = 0.2; //0.7; + vector<vector<RevEngPoint*> > nearpts(nmbpt); + bool smoothcurv = true; //false; + if (smoothcurv) + { + for (int ki=0; ki<nmbpt; ++ki) + { + RevEngPoint *pt = dynamic_cast<RevEngPoint*>((*tri_sf_)[ki]); + + // Fetch nearby points + double local_len = pt->getMeanEdgLen(); + double radius = 0.5*radius_fac*rfac_*(local_len + mean_edge_len_); + radius = std::min(radius, 20.0*mean_edge_len_); + pt->fetchClosePoints2(radius, min_next_/2, max_next_/2, nearpts[ki]); + if (nearpts[ki].size() == 0) + continue; + vector<double> H0(nearpts[ki].size()+1); + vector<double> K0(nearpts[ki].size()+1); + H0[0] = pt->meanCurvature0(); + K0[0] = pt->GaussCurvature0(); + for (size_t kj=0; kj<nearpts[ki].size(); ++kj) + { + H0[kj+1] = nearpts[ki][kj]->meanCurvature0(); + K0[kj+1] = nearpts[ki][kj]->GaussCurvature0(); + } + std::sort(H0.begin(), H0.end()); + std::sort(K0.begin(), K0.end()); + pt->setMeanCurvature(0.5*H0[H0.size()/2] + H0[(H0.size()+1)/2]); + pt->setGaussCurvature(0.5*K0[K0.size()/2] + K0[(K0.size()+1)/2]); + } + + for (int ki=0; ki<nmbpt; ++ki) + { + RevEngPoint *pt = dynamic_cast<RevEngPoint*>((*tri_sf_)[ki]); + pt->updateCurvature(); + } + + int nmbsmooth = (model_character_ <= MEDIUM_ROUGH) ? 2 : 5; + for (int ka=0; ka<nmbsmooth; ++ka) + { + for (int ki=0; ki<nmbpt; ++ki) + { + RevEngPoint *pt = dynamic_cast<RevEngPoint*>((*tri_sf_)[ki]); + + // Fetch nearby points + double Hmean = pt->meanCurvature0(); + double Kmean = pt->GaussCurvature0(); + for (size_t kj=0; kj<nearpts[ki].size(); ++kj) + { + Hmean += nearpts[ki][kj]->meanCurvature0(); + Kmean += nearpts[ki][kj]->GaussCurvature0(); + } + Hmean /= (double)(nearpts[ki].size()+1); + Kmean /= (double)(nearpts[ki].size()+1); + pt->setMeanCurvature(Hmean); + pt->setGaussCurvature(Kmean); + } + for (int ki=0; ki<nmbpt; ++ki) + { + RevEngPoint *pt = dynamic_cast<RevEngPoint*>((*tri_sf_)[ki]); + pt->updateCurvature(); + } + } + } +} + + +//=========================================================================== +void RevEng::edgeClassification() +//=========================================================================== +{ + int nmbpts = tri_sf_->size(); + vector<Vector3D> triangcorners; + vector<Vector3D> curvaturecorners; + for (int ki=0; ki<nmbpts; ++ki) + { + RevEngPoint *pt = dynamic_cast<RevEngPoint*>((*tri_sf_)[ki]); + Vector3D xyz = pt->getPoint(); + + if (pt->getTriangAngle() > norm_ang_lim_) + triangcorners.push_back(xyz); + + // Curvature edge classification + double avlen = pt->getMeanEdgLen(); + double maxpc = std::max(fabs(pt->maxPrincipalCurvature()), + fabs(pt->minPrincipalCurvature())); + double crvrad = 1.0/maxpc; + int c1_edge = (crvrad < cfac_*avlen) ? C1_EDGE : C1_NOT_EDGE; + if (c1_edge == C1_EDGE) + curvaturecorners.push_back(xyz); + + + // Store classification in point + pt->setEdgeClassification(c1_edge); + } + + // Specify/clean edge classification + bool closeedge = false; + int nmbedge = 2; + for (int ka=0; ka<nmbpts; ++ka) + { + RevEngPoint *pt = dynamic_cast<RevEngPoint*>((*tri_sf_)[ka]); + if (pt->isEdge(edge_class_type_)) + { + if (pt->isolatedEdge(edge_class_type_, nmbedge, closeedge)) + pt->setEdgeUndef(); + + else + // If the angular difference between triangle normals is less + // then the limit, classify the point as CLOSE_EDGE. + pt->adjustWithTriangNorm(norm_ang_lim_); + } + } + + vector<Vector3D> edgepts; + for (int ka=0; ka<nmbpts; ++ka) + { + RevEngPoint *pt = dynamic_cast<RevEngPoint*>((*tri_sf_)[ka]); + if (pt->isEdge(edge_class_type_)) + edgepts.push_back(pt->getPoint()); + } + + +#ifdef DEBUG_ENHANCE + std::ofstream of2("triangcorners.g2"); + of2 << "400 1 0 4 0 0 0 255" << std::endl; + of2 << triangcorners.size() << std::endl; + for (size_t kj=0; kj<triangcorners.size(); ++kj) + of2 << triangcorners[kj] << std::endl; + + std::ofstream of3("curvaturecorners.g2"); + of3 << "400 1 0 4 10 10 10 255" << std::endl; + of3 << curvaturecorners.size() << std::endl; + for (size_t kj=0; kj<curvaturecorners.size(); ++kj) + of3 << curvaturecorners[kj] << std::endl; +#endif + +#ifdef DEBUG_EDGE0 + if (edgepts.size() > 0) + { + std::ofstream ofedg("edgepts.g2"); + ofedg << "400 1 0 4 255 0 0 255" << std::endl; + ofedg << edgepts.size() << std::endl; + for (size_t kr=0; kr<edgepts.size();++kr) + ofedg << edgepts[kr] << std::endl; + } +#endif + int stop_break = 1; + } + +//=========================================================================== +void RevEng::classifyPoints() +//=========================================================================== +{ + // First extract obvious edges + edgeClassification(); + + // Fetch relevant values for all points + vector<vector<Vector3D> > class_pts(9); + int nmbpts = tri_sf_->size(); + for (int ki=0; ki<nmbpts; ++ki) + { + RevEngPoint *pt = dynamic_cast<RevEngPoint*>((*tri_sf_)[ki]); + Vector3D xyz = pt->getPoint(); + + // Curvature surface classification + int ctype = C1_UNDEF; + double gausscurv = pt->GaussCurvature(); + double meancurv = pt->meanCurvature(); + if (meancurv < -zero_H_) + { + if (gausscurv > zero_K_) + { + ctype = C1_PEAK; + class_pts[0].push_back(xyz); + } + else if (gausscurv < -zero_K_) + { + ctype = C1_SRIDGE; + class_pts[2].push_back(xyz); + } + else + { + ctype = C1_RIDGE; + class_pts[1].push_back(xyz); + } + } + else if (meancurv > zero_H_) + { + if (gausscurv > zero_K_) + { + ctype = C1_PIT; + class_pts[6].push_back(xyz); + } + else if (gausscurv < -zero_K_) + { + ctype = C1_SVALLEY; + class_pts[8].push_back(xyz); + } + else + { + ctype = C1_VALLEY; + class_pts[7].push_back(xyz); + } + } + else + { + if (gausscurv > zero_K_) + { + ctype = C1_NONE; + class_pts[3].push_back(xyz); + } + else if (gausscurv < -zero_K_) + { + ctype = C1_MINSURF; + class_pts[5].push_back(xyz); + } + else + { + ctype = C1_FLAT; + class_pts[4].push_back(xyz); + } + } + + + + // Store classification in point + pt->setClassification(ctype); + } + +#ifdef DEBUG_SEG + std::ofstream of("curvature_segments.g2"); + for (int ka=0; ka<3; ++ka) + for (int kb=0; kb<3; ++kb) + { + of << "400 1 0 4 "; + for (int kc=0; kc<3; ++kc) + of << colors[3*ka+kb][kc] << " "; + of << "255" << std::endl; + of << class_pts[3*ka+kb].size() << std::endl; + for (size_t kr=0; kr<class_pts[3*ka+kb].size(); ++kr) + of << class_pts[3*ka+kb][kr] << std::endl; + } + + + #endif + int stop_break = 1; +} + +struct +{ + bool operator()(shared_ptr<RevEngRegion> a, shared_ptr<RevEngRegion> b) + { + return (a->numPoints() > b->numPoints()); + // return 1; + // else if (a->numPoints() == b->numPoints()) + // return 2; + // else + // return 3; + } +} sort_region; + +//=========================================================================== +void RevEng::setApproxTolerance() +//=========================================================================== +{ + double eps = getInitApproxTol(); +#ifdef DEBUG + std::cout << "Approx tol: " << eps << std::endl; +#endif + // std::cout << "New tolerance: " << std::endl; + // std::cin >> eps; + setApproxTol(eps); +} + +//=========================================================================== +double RevEng::getInitApproxTol() +//=========================================================================== +{ + int nmbpts = tri_sf_->size(); + vector<double> pointdist; + double maxdist = 0.0; + double avptdist = 0.0; + double minptdist = std::numeric_limits<double>::max(); + double maxptdist = 0.0; + for (int ki=0; ki<nmbpts; ++ki) + { + RevEngPoint *pt = dynamic_cast<RevEngPoint*>((*tri_sf_)[ki]); + if (!pt->isEdge(edge_class_type_)) + { + double ptdist = pt->getPointDistance(); + pointdist.push_back(ptdist); + minptdist = std::min(minptdist, ptdist); + maxptdist = std::max(maxptdist, ptdist); + avptdist += ptdist; + } + } + if (pointdist.size() > 0) + avptdist /= (double)pointdist.size(); + + std::sort(pointdist.begin(), pointdist.end()); + + std::sort(pointdist.begin(), pointdist.end()); + double dlim = 0.93; //0.75; + int dix = (int)(dlim*(double)pointdist.size()); + double eps = pointdist[dix]; + if (model_character_ == MEDIUM_ROUGH) + eps *= 1.5; + else if (model_character_ == ROUGH) + eps *= 2.0; + + // Just to test + //eps = 0.1; + +#ifdef DEBUG_DIV + std::cout << "Maxptdist: " << maxdist << ", avdist: " << avptdist; + std::cout << ", medptdist: " << pointdist[pointdist.size()/2]; + std::cout << ", eps: " << eps << std::endl; + + std::ofstream ofd("ptdist.g2"); +#endif + double ptd1 = minptdist; + double ptd2 = maxptdist; + int nmbd = 12; + double pdel = (ptd2 - ptd1)/(double)nmbd; + vector<vector<Vector3D> > ptrs(nmbd); + for (int ki=0; ki<nmbpts; ++ki) + { + RevEngPoint *pt = dynamic_cast<RevEngPoint*>((*tri_sf_)[ki]); + Vector3D xyz = pt->getPoint(); + double dd = pt->getPointDistance(); + int ix = (int)((dd-ptd1)/pdel); + ix = std::min(ix, nmbd-1); + ptrs[ix].push_back(xyz); + } + +#ifdef DEBUG_DIV + for (int ki=0; ki<nmbd; ++ki) + { + if (ptrs[ki].size() > 0) + { + ofd << "400 1 0 4 " << colors[ki][0] << " " << colors[ki][1] << " "; + ofd << colors[ki][2] << " 255" << std::endl; + ofd << ptrs[ki].size(); + for (size_t kr=0; kr<ptrs[ki].size(); ++kr) + ofd << ptrs[ki][kr] << std::endl; + } + } +#endif + + return eps; + } + +//=========================================================================== +void RevEng::segmentIntoRegions() +//=========================================================================== +{ + // Collect continous regions + //int min_point_in = 50; //10; //20; // Should be set depending on the total + // number of points. Probably class parameter. Need to look at the use + int nmbpts = tri_sf_->size(); + for (int ki=0; ki<nmbpts; ++ki) + { + RevEngPoint *pt = dynamic_cast<RevEngPoint*>((*tri_sf_)[ki]); + if (pt->hasRegion()) + continue; + if (pt->closeEdge(edge_class_type_)) + continue; + + if (pt->nmbSameClassification(classification_type_) == 0) + single_points_.push_back(pt); + else + { + shared_ptr<RevEngRegion> region(new RevEngRegion(classification_type_, + edge_class_type_)); + pt->setRegion(region.get()); + region->collect(pt); + if (region->numPoints() == 1) + { + RevEngPoint *pt_single = region->getPoint(0); + pt_single->unsetRegion(); + single_points_.push_back(pt_single); + } + else + regions_.push_back(region); + } + } + + std::sort(regions_.begin(), regions_.end(), sort_region); +#ifdef DEBUG + if (regions_.size() > 0) + { + std::cout << "Regions 1" << std::endl; + std::ofstream of("regions1.g2"); + std::ofstream ofm("mid_regions1.g2"); + std::ofstream ofs("small_regions1.g2"); + writeRegionStage(of, ofm, ofs); + } +#endif + + // Sort regions according to number of points + std::sort(regions_.begin(), regions_.end(), sort_region); + + min_point_region_ = setSmallRegionNumber(); +#ifdef DEBUG + std::cout << "Min point region: " << min_point_region_ << std::endl; +#endif +#ifdef DEBUG_PLANAR + std::ofstream ofpc("cand_planar.g2"); +#endif + double lim_cone = 0.1*M_PI; + size_t numreg = regions_.size(); + for (size_t ki=0; ki<numreg; ++ki) + { + double avH, avK, MAH, MAK; + regions_[ki]->getAvCurvatureInfo(avH, avK, MAH, MAK); + if (regions_[ki]->numPoints() > min_point_region_ && + (regions_[ki]->planartype() || MAH <= zero_H_) && + (!regions_[ki]->feasiblePlane(zero_H_, zero_K_))) + { +#ifdef DEBUG_PLANAR + regions_[ki]->writeRegionPoints(ofpc); +#endif + vector<vector<RevEngPoint*> > other_groups; + vector<RevEngPoint*> single; + regions_[ki]->splitPlanar(lim_cone, min_point_region_/2, other_groups, single); + if (other_groups.size() > 0) + { + vector<HedgeSurface*> dummy; + surfaceExtractOutput((int)ki, other_groups, dummy); + } + if (single.size()) + single_points_.insert(single_points_.end(), single.begin(), single.end()); + + int stop_cand_plane = 1; + } + } + + // Set adjacency between regions + for (size_t ki=0; ki<regions_.size(); ++ki) + { + regions_[ki]->setRegionAdjacency(); + } + +#ifdef DEBUG_PLANAR + std::ofstream ofp("planar_reg.g2"); + for (size_t ki=0; ki<regions_.size(); ++ki) + { + if (regions_[ki]->feasiblePlane(zero_H_, zero_K_)) + regions_[ki]->writeRegionPoints(ofp); + } +#endif + // Integrate single points when appropriate + vector<RevEngPoint*> remaining_single; + for (int ka=0; ka<(int)single_points_.size(); ++ka) + { + bool merged = single_points_[ka]->mergeWithAdjacent(mean_edge_len_); + if (!merged) + { + single_points_[ka]->setOutlier(); + remaining_single.push_back(single_points_[ka]); + } + } + std::swap(single_points_, remaining_single); + + // Merge adjacent planar regions + for (int ki=0; ki<(int)regions_.size(); ++ki) + { + if (regions_[ki]->feasiblePlane(zero_H_, zero_K_)) + { + vector<RevEngRegion*> grown_regions; + vector<HedgeSurface*> adj_surfs; + bool merged = regions_[ki]->mergePlanarReg(zero_H_, zero_K_, + approx_tol_, mainaxis_, + grown_regions); + if (merged) + { + if (grown_regions.size() > 0 || adj_surfs.size() > 0) + updateRegionsAndSurfaces(ki, grown_regions, adj_surfs); + regions_[ki]->updateRegionAdjacency(); + } + } + } + + std::sort(regions_.begin(), regions_.end(), sort_region); + +#ifdef DEBUG + checkConsistence("Regions1_2"); + + if (regions_.size() > 0) + { + std::cout << "Regions 1_2" << std::endl; + std::ofstream of("regions1_2.g2"); + std::ofstream ofm("mid_regions1_2.g2"); + std::ofstream ofs("small_regions1_2.g2"); + writeRegionStage(of, ofm, ofs); + } +#endif + + // Update adjacency between regions + for (size_t ki=0; ki<regions_.size(); ++ki) + { + regions_[ki]->clearRegionAdjacency(); + } + for (size_t ki=0; ki<regions_.size(); ++ki) + { + regions_[ki]->setRegionAdjacency(); + } + + // Simplify regions structure +#ifdef DEBUG + std::cout << "Number of regions pre integrate: " << regions_.size() << std::endl; +#endif + int num_reg = (int)regions_.size(); + for (int ka=num_reg-1; ka>=0; --ka) + { + bool to_be_removed = regions_[ka]->integrateInAdjacent(mean_edge_len_, + min_next_, max_next_, + approx_tol_, 0.5, + max_nmb_outlier_); + if (to_be_removed) + { + regions_[ka]->removeFromAdjacent(); + regions_[ka]->clearRegionAdjacency(); + if (ka < num_reg-1) + std::swap(regions_[ka], regions_[num_reg-1]); + num_reg--; + } + } + if (num_reg < (int)regions_.size()) + regions_.erase(regions_.begin()+num_reg, regions_.end()); +#ifdef DEBUG + std::cout << "Number of regions post integrate: " << regions_.size() << std::endl; +#endif + std::sort(regions_.begin(), regions_.end(), sort_region); + +#ifdef DEBUG + checkConsistence("Regions2"); + + if (regions_.size() > 0) + { + std::cout << "Regions 2" << std::endl; + std::ofstream of("regions2.g2"); + std::ofstream ofm("mid_regions2.g2"); + std::ofstream ofs("small_regions2.g2"); + writeRegionStage(of, ofm, ofs); + } +#endif + + // Update adjacency between regions + for (size_t ki=0; ki<regions_.size(); ++ki) + { + regions_[ki]->clearRegionAdjacency(); + } + for (size_t ki=0; ki<regions_.size(); ++ki) + { + regions_[ki]->setRegionAdjacency(); + } + + // Update minimum number of points in region for surface generation. + // First sort regions according to number of points + std::sort(regions_.begin(), regions_.end(), sort_region); + + min_point_region_ = setSmallRegionNumber(); +#ifdef DEBUG + std::cout << "Min point region (2): " << min_point_region_ << std::endl; +#endif +} + + +//=========================================================================== +void RevEng::initialSurfaces() +//=========================================================================== +{ + // Update adjacency between regions + for (size_t ki=0; ki<regions_.size(); ++ki) + { + regions_[ki]->clearRegionAdjacency(); + } + for (size_t ki=0; ki<regions_.size(); ++ki) + { + regions_[ki]->setRegionAdjacency(); + } + + // Create surfaces in simple regions (planes and cylinders) and extract + // deviant points + int min_point_in = 50; //10; //20; // Should be set depending on the total + // number of points. Probably class parameter. Need to look at the use + double angtol = 5.0*anglim_; + //int regsize = (int)regions_.size(); + std::sort(regions_.begin(), regions_.end(), sort_region); +#ifdef DEBUG + for (size_t ki=0; ki<regions_.size(); ++ki) + { + RevEngRegion *first = regions_[ki]->getPoint(0)->region(); + int num = regions_[ki]->numPoints(); + for (int ka=1; ka<num; ++ka) + if (regions_[ki]->getPoint(ka)->region() != first) + std::cout << "Inconsistent region pointers, pre initPlaneCyl: " << ki << " " << ka << std::endl; + } +#endif + for (int kr=0; kr<(int)regions_.size(); ++kr) + { +#ifdef DEBUG + std::ofstream of0("init_reg.g2"); + regions_[kr]->writeRegionInfo(of0); +#endif + + if (regions_[kr]->numPoints() < min_point_region_) + continue; + + vector<vector<RevEngPoint*> > out_groups; + vector<RevEngPoint*> single; + vector<shared_ptr<HedgeSurface> > sfs; + vector<HedgeSurface*> prev_sfs; + bool repeat = false; + regions_[kr]->initPlaneCyl(min_point_in, min_point_region_, + approx_tol_, angtol, mainaxis_, + zero_H_, zero_K_, sfs, out_groups, single, repeat); + if (single.size() > 0) + single_points_.insert(single_points_.end(), single.begin(), single.end()); + if (out_groups.size() > 0 || prev_sfs.size() > 0) + surfaceExtractOutput((int)kr, out_groups, prev_sfs); + +#ifdef DEBUG_CHECK + bool connect = regions_[kr]->isConnected(); + if (!connect) + std::cout << "initPlaneCyl, disconnected region " << kr << std::endl; +#endif + if (sfs.size() > 0) + surfaces_.insert(surfaces_.end(), sfs.begin(), sfs.end()); + if (repeat) + --kr; + } + + std::sort(regions_.begin(), regions_.end(), sort_region); + +#ifdef DEBUG + checkConsistence("Regions3"); + + if (regions_.size() > 0) + { + std::cout << "Regions 3" << std::endl; + std::ofstream of("regions3.g2"); + std::ofstream ofm("mid_regions3.g2"); + std::ofstream ofs("small_regions3.g2"); + writeRegionStage(of, ofm, ofs); + std::ofstream of0("regions3_helix.g2"); + for (int ki=0; ki<(int)regions_.size(); ++ki) + { + if (regions_[ki]->getSurfaceFlag() == PROBABLE_HELIX) + { + regions_[ki]->writeRegionInfo(of0); + if (regions_[ki]->hasSurface()) + regions_[ki]->writeSurface(of0); + } + } + } + + if (single_points_.size() > 0) + { + std::ofstream of_single("single_pts3.g2"); + of_single << "400 1 0 4 0 0 0 255" << std::endl; + of_single << single_points_.size() << std::endl; + for (size_t kr=0; kr<single_points_.size(); ++kr) + of_single << single_points_[kr]->getPoint() << std::endl; + } + + if (surfaces_.size() > 0) + { + std::ofstream of("regsurf3.g2"); + writeRegionWithSurf(of); + } +#endif + +#ifdef DEBUG + for (int ki=0; ki<(int)regions_.size(); ++ki) + { + std::set<RevEngPoint*> tmpset(regions_[ki]->pointsBegin(), regions_[ki]->pointsEnd()); + if ((int)tmpset.size() != regions_[ki]->numPoints()) + std::cout << "Point number mismatch, regions 3. " << ki << " " << tmpset.size() << " " << regions_[ki]->numPoints() << std::endl; + int num = regions_[ki]->numPoints(); + for (int ka=0; ka<num; ++ka) + if (regions_[ki]->getPoint(ka)->region() != regions_[ki].get()) + std::cout << "Inconsistent region pointers, post initPlaneCyl: " << ki << " " << ka << std::endl; + } +#endif + + // Integrate single points when appropriate + vector<RevEngPoint*> remaining_single; + for (int ka=0; ka<(int)single_points_.size(); ++ka) + { + if (single_points_[ka]->isOutlier()) + continue; + bool merged = single_points_[ka]->mergeWithAdjacent(mean_edge_len_); + if (!merged) + { + single_points_[ka]->setOutlier(); + remaining_single.push_back(single_points_[ka]); + } + } + std::swap(single_points_, remaining_single); + + // Sort regions according to number of points + std::sort(regions_.begin(), regions_.end(), sort_region); + +#ifdef DEBUG + if (surfaces_.size() > 0) + { + std::ofstream of("regsurf4_0.g2"); + writeRegionWithSurf(of); + } +#endif + + // Update adjacency between regions + for (size_t ki=0; ki<regions_.size(); ++ki) + { + regions_[ki]->clearRegionAdjacency(); + } + for (size_t ki=0; ki<regions_.size(); ++ki) + { + regions_[ki]->setRegionAdjacency(); + } +} + +//=========================================================================== +void RevEng::growSurfaces() +//=========================================================================== +{ + // Update adjacency between regions + for (size_t ki=0; ki<regions_.size(); ++ki) + { + regions_[ki]->clearRegionAdjacency(); + } + for (size_t ki=0; ki<regions_.size(); ++ki) + { + regions_[ki]->setRegionAdjacency(); + } + + //int min_point_in = 50; //10; //20; // Should be set depending on the total + // number of points. Probably class parameter. Need to look at the use + double angtol = 5.0*anglim_; + + bool joinreg = true; + if (joinreg) + { +#ifdef DEBUG + std::cout << "Pre join. Number of regions: " << regions_.size() << std::endl; +#endif + // int num_reg = (int)regions_.size(); + for (int ki=0; ki<(int)regions_.size(); ++ki) + { +#ifdef DEBUG + std::ofstream of0("init_join.g2"); + regions_[ki]->writeRegionInfo(of0); +#endif + if (regions_[ki]->numPoints() < min_point_region_) + continue; // Grow into larger + + if (regions_[ki]->hasSurface()) + { + growSurface(ki); +#ifdef DEBUG_CHECK + int num = regions_[ki]->numPoints(); + for (int ka=0; ka<num; ++ka) + if (regions_[ki]->getPoint(ka)->region() != regions_[ki].get()) + std::cout << "Inconsistent region pointers, post grow: " << ki << " " << ka << std::endl; +#endif + } + // else + // { + // vector<RevEngRegion*> adapted_regions; + // regions_[ki]->joinRegions(mainaxis_, approx_tol_, + // angtol, adapted_regions); + // for (size_t kj=0; kj<adapted_regions.size(); ++kj) + // { + // size_t kr=0; + // for (kr=0; kr<regions_.size(); ++kr) + // if (adapted_regions[kj] == regions_[kr].get()) + // break; + + // if (kr < regions_.size()) + // { + // // std::swap(regions_[kr], regions_[num_reg-1]); + // // num_reg--; + // regions_.erase(regions_.begin()+kr); + // } + // } + // } +#ifdef DEBUG + std::ofstream of02("post_join.g2"); + regions_[ki]->writeRegionInfo(of02); +#endif + int stop_grow = 1; + } + // if (num_reg < (int)regions_.size()) + // regions_.erase(regions_.begin()+num_reg, regions_.end()); +#ifdef DEBUG + std::cout << "Post join. Number of regions: " << regions_.size() << std::endl; + + checkConsistence("Regions4"); + + if (regions_.size() > 0) + { + std::cout << "Regions 4" << std::endl; + std::ofstream of("regions4.g2"); + std::ofstream ofm("mid_regions4.g2"); + std::ofstream ofs("small_regions4.g2"); + writeRegionStage(of, ofm, ofs); + if (surfaces_.size() > 0) + { + std::ofstream of("regsurf4.g2"); + writeRegionWithSurf(of); + } + std::ofstream of0("regions4_helix.g2"); + for (int ki=0; ki<(int)regions_.size(); ++ki) + { + if (regions_[ki]->getSurfaceFlag() == PROBABLE_HELIX) + { + regions_[ki]->writeRegionInfo(of0); + if (regions_[ki]->hasSurface()) + regions_[ki]->writeSurface(of0); + } + } + } +#endif + } +#ifdef DEBUG_CHECK + for (size_t ki=0; ki<regions_.size(); ++ki) + { + int num = regions_[ki]->numPoints(); + for (int ka=0; ka<num; ++ka) + if (regions_[ki]->getPoint(ka)->region() != regions_[ki].get()) + std::cout << "Inconsistent region pointers, post grow: " << ki << " " << ka << std::endl; + } + + for (int ki=0; ki<(int)regions_.size(); ++ki) + { + std::set<RevEngPoint*> tmpset(regions_[ki]->pointsBegin(), regions_[ki]->pointsEnd()); + if ((int)tmpset.size() != regions_[ki]->numPoints()) + std::cout << "Point number mismatch, regions 4. " << ki << " " << tmpset.size() << " " << regions_[ki]->numPoints() << std::endl; + } +#endif + + // Update adjacency between regions + for (size_t ki=0; ki<regions_.size(); ++ki) + { + regions_[ki]->clearRegionAdjacency(); + } + for (size_t ki=0; ki<regions_.size(); ++ki) + { + regions_[ki]->setRegionAdjacency(); + } + + + for (int ki=0; ki<(int)regions_.size(); ++ki) + { + if (regions_[ki]->hasSurface()) + { + vector<RevEngRegion*> grown_regions; + vector<HedgeSurface*> adj_surfs; + vector<RevEngEdge*> adj_edgs; + regions_[ki]->mergeAdjacentSimilar(approx_tol_, angtol, + grown_regions, adj_surfs, adj_edgs); + if (grown_regions.size() > 0 || adj_surfs.size() > 0) + updateRegionsAndSurfaces(ki, grown_regions, adj_surfs); + for (size_t kr=0; kr<adj_edgs.size(); ++kr) + { + size_t kj; + for (kj=0; kj<edges_.size(); ++kj) + if (edges_[kj].get() == adj_edgs[kr]) + break; + if (kj < edges_.size()) + edges_.erase(edges_.begin()+kj); + } + } + } + +#ifdef DEBUG_CHECK + for (size_t ki=0; ki<regions_.size(); ++ki) + { + int num = regions_[ki]->numPoints(); + for (int ka=0; ka<num; ++ka) + if (regions_[ki]->getPoint(ka)->region() != regions_[ki].get()) + std::cout << "Inconsistent region pointers, post mergeAdjacentSimilar: " << ki << " " << ka << std::endl; + } + + for (int ki=0; ki<(int)regions_.size(); ++ki) + { + std::set<RevEngPoint*> tmpset(regions_[ki]->pointsBegin(), regions_[ki]->pointsEnd()); + if ((int)tmpset.size() != regions_[ki]->numPoints()) + std::cout << "Point number mismatch, regions 4_2. " << ki << " " << tmpset.size() << " " << regions_[ki]->numPoints() << std::endl; + } +#endif + +#ifdef DEBUG + std::cout << "Post merge similar. Number of regions: " << regions_.size() << std::endl; + + checkConsistence("Regions4_2"); + + if (regions_.size() > 0) + { + std::cout << "Regions 4_2" << std::endl; + std::ofstream of("regions4_2.g2"); + std::ofstream ofm("mid_regions4_2.g2"); + std::ofstream ofs("small_regions4_2.g2"); + writeRegionStage(of, ofm, ofs); + std::ofstream of0("regions4_2_helix.g2"); + for (int ki=0; ki<(int)regions_.size(); ++ki) + { + if (regions_[ki]->getSurfaceFlag() == PROBABLE_HELIX) + { + regions_[ki]->writeRegionInfo(of0); + if (regions_[ki]->hasSurface()) + regions_[ki]->writeSurface(of0); + } + } + } + if (surfaces_.size() > 0) + { + std::ofstream of("regsurf4_2.g2"); + writeRegionWithSurf(of); + } +#endif + + // Update adjacency between regions + for (size_t ki=0; ki<regions_.size(); ++ki) + { + regions_[ki]->clearRegionAdjacency(); + } + for (size_t ki=0; ki<regions_.size(); ++ki) + { + regions_[ki]->setRegionAdjacency(); + } + + for (int ki=0; ki<(int)regions_.size(); ++ki) + { +#ifdef DEBUG + std::ofstream ofp("init_growplane.g2"); + regions_[ki]->writeRegionInfo(ofp); +#endif + if (regions_[ki]->numPoints() < min_point_region_) + continue; // Not a stable source + + if (!regions_[ki]->hasSurface()) + continue; + + vector<RevEngRegion*> grown_regions; + vector<HedgeSurface*> adj_surfs; + vector<vector<RevEngPoint*> > added_groups; + regions_[ki]->growPlaneOrCyl(mainaxis_, min_point_region_, approx_tol_, + angtol, grown_regions, adj_surfs, + added_groups); + updateRegionsAndSurfaces(ki, grown_regions, adj_surfs); + vector<HedgeSurface*> dummy_surfs; + if (added_groups.size() > 0) + surfaceExtractOutput((int)ki, added_groups, dummy_surfs); + int stop_grow = 1; +} + +#ifdef DEBUG + std::cout << "Grow plane. Number of regions: " << regions_.size() << std::endl; + + checkConsistence("Regions4_3"); + + if (regions_.size() > 0) + { + std::cout << "Regions 4_3" << std::endl; + std::ofstream of("regions4_3.g2"); + std::ofstream ofm("mid_regions4_3.g2"); + std::ofstream ofs("small_regions4_3.g2"); + writeRegionStage(of, ofm, ofs); + std::ofstream of0("regions4_3_helix.g2"); + for (int ki=0; ki<(int)regions_.size(); ++ki) + { + if (regions_[ki]->getSurfaceFlag() == PROBABLE_HELIX) + { + regions_[ki]->writeRegionInfo(of0); + if (regions_[ki]->hasSurface()) + regions_[ki]->writeSurface(of0); + } + } + } + if (surfaces_.size() > 0) + { + std::ofstream of("regsurf4_3.g2"); + writeRegionWithSurf(of); + } +#endif + + // Update adjacency between regions + for (size_t ki=0; ki<regions_.size(); ++ki) + { + regions_[ki]->clearRegionAdjacency(); + } + for (size_t ki=0; ki<regions_.size(); ++ki) + { + regions_[ki]->setRegionAdjacency(); + } + + // Simplify regions structure +#ifdef DEBUG + std::cout << "Number of regions pre integrate: " << regions_.size() << std::endl; +#endif + int num_reg = (int)regions_.size(); + for (int ka=num_reg-1; ka>=0; --ka) + { + HedgeSurface* hedge = (regions_[ka]->hasSurface()) ? + regions_[ka]->getSurface(0) : 0; + bool to_be_removed = regions_[ka]->integrateInAdjacent(mean_edge_len_, + min_next_, max_next_, + approx_tol_, 0.5, + max_nmb_outlier_); + if (to_be_removed) + { + regions_[ka]->removeFromAdjacent(); + regions_[ka]->clearRegionAdjacency(); + if (hedge) + { + size_t kr; + for (kr=0; kr<surfaces_.size(); ++kr) + if (surfaces_[kr].get() == hedge) + break; + if (kr < surfaces_.size()) + surfaces_.erase(surfaces_.begin()+kr); + } + + if (ka < num_reg-1) + std::swap(regions_[ka], regions_[num_reg-1]); + num_reg--; + } + } + if (num_reg < (int)regions_.size()) + regions_.erase(regions_.begin()+num_reg, regions_.end()); +#ifdef DEBUG + std::cout << "Number of regions post integrate: " << regions_.size() << std::endl; + + checkConsistence("Regions5"); + + if (regions_.size() > 0) + { + std::cout << "Regions 5" << std::endl; + std::ofstream of("regions5.g2"); + std::ofstream ofm("mid_regions5.g2"); + std::ofstream ofs("small_regions5.g2"); + writeRegionStage(of, ofm, ofs); + if (surfaces_.size() > 0) + { + std::ofstream of("regsurf5.g2"); + writeRegionWithSurf(of); + } + } +#endif + +#ifdef DEBUG + for (int ki=0; ki<(int)regions_.size(); ++ki) + { + std::set<RevEngPoint*> tmpset(regions_[ki]->pointsBegin(), regions_[ki]->pointsEnd()); + if ((int)tmpset.size() != regions_[ki]->numPoints()) + std::cout << "Point number mismatch, regions 5. " << ki << " " << tmpset.size() << " " << regions_[ki]->numPoints() << std::endl; + } +#endif + std::sort(regions_.begin(), regions_.end(), sort_region); + + // Update adjacency between regions + for (size_t ki=0; ki<regions_.size(); ++ki) + { + regions_[ki]->clearRegionAdjacency(); + } + for (size_t ki=0; ki<regions_.size(); ++ki) + { + regions_[ki]->setRegionAdjacency(); + } + + + int stop_break2 = 1; +} + + +//=========================================================================== +void RevEng::updateAxesAndSurfaces() +//=========================================================================== +{ + // Update adjacency between regions + for (size_t ki=0; ki<regions_.size(); ++ki) + { + regions_[ki]->clearRegionAdjacency(); + } + for (size_t ki=0; ki<regions_.size(); ++ki) + { + regions_[ki]->setRegionAdjacency(); + } + + // // First extract low accuracy points from groups with surface + double angtol = 5.0*anglim_; + // for (size_t ki=0; ki<regions_.size(); ++ki) + // { + // if (!regions_[ki]->hasSurface()) + // continue; + + // vector<vector<RevEngPoint*> > added_groups; + // vector<HedgeSurface*> dummy_surfs; + // regions_[ki]->removeLowAccuracyPoints(min_point_region_, + // approx_tol_, angtol, added_groups); + // if (added_groups.size() > 0) + // surfaceExtractOutput((int)ki, added_groups, dummy_surfs); + // } + + std::sort(regions_.begin(), regions_.end(), sort_region); + + vector<int> reg_size(surfaces_.size()); + for (size_t ki=0; ki<surfaces_.size(); ++ki) + reg_size[ki] = surfaces_[ki]->numPoints(); + + std::sort(reg_size.begin(), reg_size.end()); + + Point axis[3]; + int min_num = reg_size[(int)reg_size.size()/4]; + min_num = std::min(min_num, reg_size[reg_size.size()-1]/10); + min_num = std::max(min_num, reg_size[reg_size.size()-1]/100); + double max_ang = 0.1*M_PI; + + Point plane_axis[3]; + int num_pts1[3]; + computeAxisFromPlane(mainaxis_, min_num, max_ang, plane_axis, num_pts1); + + Point cyl_axis[3]; + int num_pts2[3]; + computeAxisFromCylinder(plane_axis, min_num, max_ang, cyl_axis, num_pts2); + + // Update main axes. Prioritize information from planes + for (int ka=0; ka<3; ++ka) + { + num_pts1[ka] *= 2; + int all_pts = num_pts1[ka] + num_pts2[ka]; + if (all_pts == 0) + continue; + double fac1 = (double)num_pts1[ka]/(double)(all_pts); + double fac2 = (double)num_pts2[ka]/(double)(all_pts); + if (cyl_axis[ka]*plane_axis[ka] < 0.0) + cyl_axis[ka] *= -1.0; + mainaxis_[ka] = fac1*plane_axis[ka] + fac2*cyl_axis[ka]; + mainaxis_[ka].normalize(); + } + + // Ensure orthogonality + for (int ka=0; ka<3; ++ka) + for (int kb=ka+1; kb<3; ++kb) + if (num_pts1[ka] + num_pts2[ka] < num_pts1[kb] + num_pts2[kb]) + { + std::swap(num_pts1[ka], num_pts1[kb]); + std::swap(num_pts2[ka], num_pts2[kb]); + std::swap(mainaxis_[ka], mainaxis_[kb]); + } + + Point tmp_axis[3]; + tmp_axis[2] = mainaxis_[0].cross(mainaxis_[1]); + tmp_axis[1] = (num_pts1[2]+num_pts2[2] > 0) ? + mainaxis_[2].cross(mainaxis_[0]) : mainaxis_[1]; + tmp_axis[0] = (num_pts1[1]+num_pts2[1] > 0 && num_pts1[2]+num_pts2[2] > 0) ? + mainaxis_[1].cross(mainaxis_[2]) : mainaxis_[0]; + for (int ka=0; ka<3; ++ka) + { + if (tmp_axis[ka]*mainaxis_[ka] < 0.0) + tmp_axis[ka] *= -1.0; + if (num_pts1[ka] + num_pts2[ka] > 0) + tmp_axis[ka] = 0.5*(tmp_axis[ka] + mainaxis_[ka]); + tmp_axis[ka].normalize(); + } + + if (num_pts1[0]+num_pts2[0] > 0 && num_pts1[1]+num_pts2[1] > 0 && + num_pts1[2]+num_pts2[2] > 0) + { + mainaxis_[0] = tmp_axis[1].cross(tmp_axis[2]); + mainaxis_[1] = tmp_axis[2].cross(tmp_axis[0]); + mainaxis_[2] = tmp_axis[0].cross(tmp_axis[1]); + for (int ka=0; ka<3; ++ka) + { + if (mainaxis_[ka]*tmp_axis[ka] < 0.0) + mainaxis_[ka] *= -1.0; + mainaxis_[ka] = 0.5*(tmp_axis[ka] + mainaxis_[ka]); + mainaxis_[ka].normalize(); + } + } + else + { + for (int ka=0; ka<3; ++ka) + { + mainaxis_[ka] = tmp_axis[ka]; + } + } + // Point tmp_axis = mainaxis_[0].cross(mainaxis_[1]); + // tmp_axis.normalize(); + // if (mainaxis_[2]*tmp_axis < 0.0) + // tmp_axis *= -1; + // mainaxis_[2] = 0.5*(mainaxis_[2] + tmp_axis); + // tmp_axis = mainaxis_[2].cross(mainaxis_[0]); + // tmp_axis.normalize(); + // if (mainaxis_[1]*tmp_axis < 0.0) + // tmp_axis *= -1; + // mainaxis_[1] = 0.5*(mainaxis_[1] + tmp_axis); + // tmp_axis = mainaxis_[1].cross(mainaxis_[2]); + // tmp_axis.normalize(); + // if (mainaxis_[0]*tmp_axis < 0.0) + // tmp_axis *= -1; + // mainaxis_[0] = 0.5*(mainaxis_[0] + tmp_axis); + + mainaxis_[2] = mainaxis_[0].cross(mainaxis_[1]); + mainaxis_[1] = mainaxis_[2].cross(mainaxis_[0]); + for (int ka=0; ka<3; ++ka) + mainaxis_[ka].normalize(); + + // Update surfaces + for (int ki=0; ki<(int)regions_.size(); ++ki) + { + if (regions_[ki]->hasSurface())// && (!regions_[ki]->hasRevEdges())) + { + /*bool updated =*/ (void)axisUpdate(ki, max_ang, angtol); + // if (updated) + // { + // growSurface(ki); + // int stop_break0 = 1; + // } + } + } + +#ifdef DEBUG + std::ofstream of0("regions5_2_0_helix.g2"); + for (int ki=0; ki<(int)regions_.size(); ++ki) + { + if (regions_[ki]->getSurfaceFlag() == PROBABLE_HELIX) + { + regions_[ki]->writeRegionInfo(of0); + if (regions_[ki]->hasSurface()) + regions_[ki]->writeSurface(of0); + } + } +#endif + + for (int ki=0; ki<(int)regions_.size(); ++ki) + { + if (regions_[ki]->hasSurface()) + { + vector<RevEngRegion*> grown_regions; + vector<HedgeSurface*> adj_surfs; + vector<RevEngEdge*> adj_edgs; + regions_[ki]->mergeAdjacentSimilar(approx_tol_, angtol, + grown_regions, adj_surfs, adj_edgs); + if (grown_regions.size() > 0 || adj_surfs.size() > 0) + { + updateRegionsAndSurfaces(ki, grown_regions, adj_surfs); + for (size_t kr=0; kr<adj_edgs.size(); ++kr) + { + size_t kj; + for (kj=0; kj<edges_.size(); ++kj) + if (edges_[kj].get() == adj_edgs[kr]) + break; + if (kj < edges_.size()) + edges_.erase(edges_.begin()+kj); + } + // if (!regions_[ki]->hasRevEdges()) + // { + bool updated = axisUpdate(ki, max_ang, angtol); + if (!updated) + int stop_break1 = 1; + // } + } + } + } +#ifdef DEBUG + std::cout << "Post merge similar. Number of regions: " << regions_.size() << std::endl; + + checkConsistence("Regions5_2"); + + if (regions_.size() > 0) + { + std::cout << "Regions 5_2" << std::endl; + std::ofstream of("regions5_2.g2"); + std::ofstream ofm("mid_regions5_2.g2"); + std::ofstream ofs("small_regions5_2.g2"); + writeRegionStage(of, ofm, ofs); + std::ofstream of0("regions5_2_helix.g2"); + for (int ki=0; ki<(int)regions_.size(); ++ki) + { + if (regions_[ki]->getSurfaceFlag() == PROBABLE_HELIX) + { + regions_[ki]->writeRegionInfo(of0); + if (regions_[ki]->hasSurface()) + regions_[ki]->writeSurface(of0); + } + } + if (surfaces_.size() > 0) + { + std::ofstream of("regsurf5_2.g2"); + writeRegionWithSurf(of); + } + } +#endif +#ifdef DEBUG + std::ofstream ofu1("unresolved.g2"); + for (size_t kr=0; kr<regions_.size(); ++kr) + { + if (regions_[kr]->hasSurface()) + continue; + if (regions_[kr]->hasAssociatedBlend()) + continue; + regions_[kr]->writeRegionPoints(ofu1); + } +#endif + int stop_break = 1; +} + + +//=========================================================================== +bool RevEng::axisUpdate(int ix, double max_ang, double angtol) +//=========================================================================== +{ + if (!regions_[ix]->hasSurface()) + return false; + + HedgeSurface *hsurf = regions_[ix]->getSurface(0); + shared_ptr<ElementarySurface> elem = + dynamic_pointer_cast<ElementarySurface,ParamSurface>(hsurf->surface()); + if (!elem.get()) + return false; + +#ifdef DEBUG_AXIS + std::ofstream of("axis_adapt.g2"); + elem->writeStandardHeader(of); + elem->write(of); + regions_[ix]->writeRegionPoints(of); +#endif + vector<pair<shared_ptr<ElementarySurface>, RevEngRegion*> > adj_elem, adj_elem_base; + regions_[ix]->getAdjacentElemInfo(adj_elem, adj_elem_base); + Point adj_axis, adj_pos; + double adj_ang = M_PI; + Point vec = elem->direction(); + double pihalf = 0.5*M_PI; + double min_perpen = M_PI; + for (size_t ki=0; ki<adj_elem.size(); ++ki) + { + if (adj_elem[ki].first->instanceType() != Class_Plane && + adj_elem[ki].first->instanceType() != Class_Cylinder) + continue; + if (adj_elem[ki].second->hasBlendEdge()) + continue; // Derived information + int sfflag = adj_elem[ki].second->getSurfaceFlag(); + double anglim = (sfflag == ACCURACY_OK) ? 2.0*max_ang : max_ang; + Point dir = adj_elem[ki].first->direction(); + double ang = vec.angle(dir); + if (fabs(pihalf - ang) < min_perpen) + min_perpen = fabs(pihalf - ang); + ang = std::min(ang, M_PI-ang); + if (ang < anglim && ang < adj_ang) + { + adj_ang = ang; + adj_axis = dir; + if (adj_elem[ki].first->instanceType() == Class_Cylinder) + adj_pos = adj_elem[ki].first->location(); + } + } + + int ka_min = -1; + double ang_main = M_PI; + for (int ka=0; ka<3; ++ka) + { + double ang = vec.angle(mainaxis_[ka]); + ang = std::min(ang, M_PI-ang); + if (ang < max_ang && ang < ang_main) + { + ang_main = ang; + ka_min = ka; + } + } + + bool updated = false; + if (adj_axis.dimension() != 0 || ka_min >= 0) + updated = regions_[ix]->updateSurfaceWithAxis(min_point_region_, adj_axis, mainaxis_, + ka_min, approx_tol_, angtol, adj_pos); + // if (updated == false && elem->instanceType() == Class_Plane && min_perpen < anglim_) + // { + // regions_[ix]->setPlaneParam(min_point_region_, mainaxis_, approx_tol_, angtol); + // } + + return updated; +} + +//=========================================================================== +void RevEng::recognizeEdges(bool only_curve) +//=========================================================================== +{ + // Ensure some limitation of surface size + Point low = bbox_.low(); + Point high = bbox_.high(); + double diag = low.dist(high); + double blendfac = 2.0; + + // Ensure bounded surfaces + for (size_t ki=0; ki<surfaces_.size(); ++ki) + surfaces_[ki]->limitSurf(diag); + + double angtol = 5.0*anglim_; + double pihalf = 0.5*M_PI; + for (size_t ki=0; ki<regions_.size(); ++ki) + { + if (!regions_[ki]->hasSurface()) + continue; + if (regions_[ki]->hasAssociatedBlend()) + continue; + if (regions_[ki]->hasBlendEdge()) + continue; + + vector<RevEngEdge*> rev_edgs1 = regions_[ki]->getAllRevEdges(); + + int code; + int classtype = regions_[ki]->getSurface(0)->instanceType(code); + if (classtype != Class_Plane && classtype != Class_Cylinder && + classtype != Class_Cone && classtype != Class_Sphere) + continue; // Preliminary + + shared_ptr<ParamSurface> surf1 = regions_[ki]->getSurface(0)->surface(); + shared_ptr<ElementarySurface> elem1 = + dynamic_pointer_cast<ElementarySurface,ParamSurface>(surf1); + Point dir1 = elem1->direction(); + if (elem1->instanceType() == Class_Plane && + dir1*regions_[ki]->getPoint(0)->getTriangNormal() < 0.0) + dir1 *= -1; + for (size_t kj=ki+1; kj<regions_.size(); ++kj) + { + bool only_curve2 = only_curve; + if (!regions_[kj]->hasSurface()) + continue; + if (regions_[ki]->hasAssociatedBlend()) + continue; + if (regions_[ki]->hasBlendEdge()) + continue; + + vector<RevEngEdge*> rev_edgs2 = regions_[kj]->getAllRevEdges(); + if (rev_edgs1.size() > 0 && rev_edgs2.size() > 0) + { + size_t kr, kh; + for (kr=0; kr<rev_edgs1.size(); ++kr) + { + for (kh=0; kh<rev_edgs2.size(); ++kh) + if (rev_edgs1[kr] == rev_edgs2[kh]) + break; + if (kh < rev_edgs2.size()) + break; + } + if (kr < rev_edgs1.size()) + continue; + } + + int code2; + int classtype2 = regions_[kj]->getSurface(0)->instanceType(code2); + if (classtype2 != Class_Plane && classtype2 != Class_Cylinder && + classtype2 != Class_Cone && classtype2 != Class_Sphere) + continue; // Preliminary + if (classtype == Class_Sphere || classtype2 == Class_Sphere) + only_curve2 = true; + if (classtype == Class_Cylinder && classtype2 == Class_Cylinder) + continue; + if (classtype == Class_Cone && classtype2 == Class_Cone) + continue; + if ((classtype == Class_Sphere && classtype2 != Class_Plane) || + (classtype2 == Class_Sphere && classtype != Class_Plane)) + continue; + +#ifdef DEBUG_EDGE + std::ofstream of1("adj_regs.g2"); + regions_[ki]->writeRegionPoints(of1); + regions_[ki]->writeSurface(of1); + regions_[kj]->writeRegionPoints(of1); + regions_[kj]->writeSurface(of1); +#endif + shared_ptr<ParamSurface> surf2 = regions_[kj]->getSurface(0)->surface(); + shared_ptr<ElementarySurface> elem2 = + dynamic_pointer_cast<ElementarySurface,ParamSurface>(surf2); + if (regions_[ki]->isAdjacent(regions_[kj].get()) + || (only_curve2 == false && + regions_[ki]->isNextToAdjacent(regions_[kj].get()))) + { + Point dir2 = elem2->direction(); + if (elem2->instanceType() == Class_Plane && + dir2*regions_[kj]->getPoint(0)->getTriangNormal() < 0.0) + dir2 *= -1; + double ang = dir1.angle(dir2); + ang = std::min(ang, M_PI-ang); + bool compute_edge = false; + if (classtype == Class_Plane && classtype2 == Class_Plane) + { + if (ang > blendfac*angtol) + compute_edge = true; + } + else if (classtype == Class_Plane || classtype2 == Class_Plane) + { + if (ang < blendfac*angtol || + (only_curve2 && fabs(pihalf-ang) > blendfac*angtol)) + compute_edge = true; + else if (fabs(pihalf-ang) < blendfac*angtol) + { + // Check for near tangential cases + Point norm = (classtype == Class_Plane) ? elem1->direction() : + elem2->direction(); + double dlen = fabs((elem1->location() - elem2->location())*norm); + double rad = (classtype == Class_Plane) ? elem2->radius(0.0, 0.0) : + elem1->radius(0.0, 0.0); // Not appropriate for a cone + if (dlen > rad + blendfac*approx_tol_ || + dlen < rad - blendfac*approx_tol_) + compute_edge = true; + } + } + else + { + // One cone and one cylinder. Check for same axis and + // a significant cone angle + Point loc1 = elem1->location(); + Point loc2 = elem2->location(); + Point tmp = loc1 + ((loc2-loc1)*dir1)*dir1; + if (ang >= blendfac*angtol || loc2.dist(tmp) > approx_tol_) + compute_edge = false; + else + { + double phi = 0.0; + shared_ptr<Cone> cone1 = + dynamic_pointer_cast<Cone,ElementarySurface>(elem1); + shared_ptr<Cone> cone2 = + dynamic_pointer_cast<Cone,ElementarySurface>(elem2); + if (cone1.get()) + phi = cone1->getConeAngle(); + else if (cone2.get()) + phi = cone2->getConeAngle(); + double conefac = 4.0; + if (fabs(phi) > conefac*angtol) + compute_edge = true; + else + compute_edge = false; + } + } + + + if (compute_edge) + { + // Make sure that cone domains do not cover the apex + int ka; + shared_ptr<ElementarySurface> elem; + shared_ptr<RevEngRegion> reg; + for (ka=0, elem=elem1, reg=regions_[ki]; ka<2; + ++ka, elem=elem2, reg=regions_[kj]) + { + if (elem->instanceType() == Class_Cone) + { + shared_ptr<Cone> cone = + dynamic_pointer_cast<Cone,ElementarySurface>(elem); + double apar; + int adir; + cone->getDegenerateParam(apar, adir); + if (adir > 0) + { + RectDomain dom = cone->getParameterBounds(); + double dom2[4]; + dom2[0] = dom.umin(); + dom2[1] = dom.umax(); + dom2[2] = dom.vmin(); + dom2[3] = dom.vmax(); + double dom3[4]; + reg->getDomain(dom3); + adir--; + // Assumes that the relevant part of the cone + // does not cover the apex + double midp = 0.5*(dom3[2*adir]+dom3[2*adir+1]); + double del = 0.01*(dom3[2*adir+1]-dom3[2*adir]); + if (midp < apar) + dom2[2*adir+1] = std::min(dom2[2*adir+1], apar-del); + else + dom2[2*adir] = std::max(dom2[2*adir], apar+del); + cone->setParameterBounds(dom2[0], dom2[2], + dom2[1], dom2[3]); + } + } + } + + vector<shared_ptr<RevEngEdge> > edges = + defineEdgesBetween(ki, elem1, dir1,kj, elem2, dir2, + only_curve2); + if (edges.size() > 0) + edges_.insert(edges_.end(), edges.begin(),edges.end()); + } + } + } + } +} + +//=========================================================================== +void RevEng::firstEdges() +//=========================================================================== +{ + // Update adjacency between regions + for (size_t ki=0; ki<regions_.size(); ++ki) + { + regions_[ki]->clearRegionAdjacency(); + } + for (size_t ki=0; ki<regions_.size(); ++ki) + { + regions_[ki]->setRegionAdjacency(); + } + + recognizeEdges(); + +#ifdef DEBUG + checkConsistence("Regions6"); + + if (regions_.size() > 0) + { + std::cout << "Regions6" << std::endl; + std::ofstream of("regions6.g2"); + std::ofstream ofm("mid_regions6.g2"); + std::ofstream ofs("small_regions6.g2"); + writeRegionStage(of, ofm, ofs); + } + + if (edges_.size() > 0) + { + std::ofstream ofe("edges6.g2"); + writeEdgeStage(ofe); + } + +#endif + + // Update adjacency between regions + for (size_t ki=0; ki<regions_.size(); ++ki) + { + regions_[ki]->clearRegionAdjacency(); + } + for (size_t ki=0; ki<regions_.size(); ++ki) + { + regions_[ki]->setRegionAdjacency(); + } + + +#ifdef DEBUG + std::cout << "Extend blend region collection" << std::endl; +#endif + for (size_t ki=0; ki<edges_.size(); ++ki) + { + extendBlendAssociation(ki); + } + + #ifdef DEBUG + checkConsistence("Regions6_1"); +#endif + + // Just in case composed regions have been segmented + int min_num_point = min_point_region_/10; + for (int ki=0; ki<(int)regions_.size(); ++ki) + { + if (regions_[ki]->hasSurface()) + continue; + if (regions_[ki]->hasAssociatedBlend()) + continue; + if (regions_[ki]->numPoints() < min_num_point) + continue; +#ifdef DEBUG_EDGE + std::ofstream of("planar_merge_cand.g2"); + regions_[ki]->writeRegionInfo(of); +#endif + if (regions_[ki]->feasiblePlane(zero_H_, zero_K_)) + { + vector<RevEngRegion*> grown_regions; + vector<HedgeSurface*> adj_surfs; + bool merged = regions_[ki]->mergePlanarReg(zero_H_, zero_K_, + approx_tol_, mainaxis_, + grown_regions); + if (merged) + { + if (grown_regions.size() > 0 || adj_surfs.size() > 0) + updateRegionsAndSurfaces(ki, grown_regions, adj_surfs); + regions_[ki]->updateRegionAdjacency(); + } + } + } + + + #ifdef DEBUG + checkConsistence("Regions6_2"); + + if (regions_.size() > 0) + { + std::cout << "Regions6_2" << std::endl; + std::ofstream of("regions6_2.g2"); + std::ofstream ofm("mid_regions6_2.g2"); + std::ofstream ofs("small_regions6_2.g2"); + writeRegionStage(of, ofm, ofs); + } + + if (edges_.size() > 0) + { + std::ofstream ofe("edges6_2.g2"); + writeEdgeStage(ofe); + } + +#endif + int stop_break = 1; +} + +//=========================================================================== +void RevEng::extendBlendAssociation(size_t ix) +//=========================================================================== +{ + // Regions in blend area + vector<RevEngRegion*> blend_regs; + edges_[ix]->getAllBlendRegs(blend_regs); + size_t num_blend_regs = blend_regs.size(); + +#ifdef DEBUG_BLEND + std::ofstream of1("blend_regs.g2"); + for (size_t kj=0; kj<blend_regs.size(); ++kj) + blend_regs[kj]->writeRegionPoints(of1); +#endif + // Intersection curve + vector<shared_ptr<CurveOnSurface> > cvs; + edges_[ix]->getCurve(cvs); +#ifdef DEBUG_BLEND + for (size_t kj=0; kj<cvs.size(); ++kj) + { + cvs[kj]->spaceCurve()->writeStandardHeader(of1); + cvs[kj]->spaceCurve()->write(of1); + } + RevEngRegion *adj1, *adj2; + edges_[ix]->getAdjacent(adj1, adj2); + adj1->writeRegionPoints(of1); + adj2->writeRegionPoints(of1); +#endif + + // Width + double width = edges_[ix]->getDistance(); + + for (size_t ki=0; ki<blend_regs.size(); ++ki) + { + vector<RevEngRegion*> new_blends; + blend_regs[ki]->neighbourBlends(cvs, 2.0*width, approx_tol_, new_blends); +#ifdef DEBUG_BLEND + std::ofstream of2("blend_regs2.g2"); + for (size_t kj=0; kj<new_blends.size(); ++kj) + new_blends[kj]->writeRegionPoints(of2); +#endif + for (size_t kj=0; kj<new_blends.size(); ++kj) + { + size_t kr; + for (kr=0; kr<blend_regs.size(); ++kr) + if (blend_regs[kr] == new_blends[kj]) + break; + if (kr == blend_regs.size()) + blend_regs.push_back(new_blends[kj]); + } + int stop_break = 1; + } + + for (size_t kj=num_blend_regs; kj<blend_regs.size(); ++kj) + { + edges_[ix]->addBlendRegion(blend_regs[kj]); + blend_regs[kj]->setAssociatedBlend(edges_[ix].get()); + } + int stop_break2 = 1; +} + +//=========================================================================== +bool RevEng::setBlendEdge(size_t ix) +//=========================================================================== +{ + Point low = bbox_.low(); + Point high = bbox_.high(); + double diag = low.dist(high); + double blendfac = 2.0; + + //double pihalf = 0.5*M_PI; + double angtol = 5.0*anglim_; + vector<pair<shared_ptr<ElementarySurface>, RevEngRegion*> > adj_elem, adj_elem_base; + regions_[ix]->getAdjacentElemInfo(adj_elem, adj_elem_base); + for (size_t ki=0; ki<adj_elem.size(); ++ki) + { + ClassType type1 = adj_elem[ki].first->instanceType(); + if (type1 != Class_Plane && type1 != Class_Cylinder) + continue; + Point dir1 = adj_elem[ki].first->direction(); + if (type1 == Class_Plane && + dir1*adj_elem[ki].second->getMeanNormalTriang() < 0.0) + dir1 *= -1; + for (size_t kj=ki+1; kj<adj_elem.size(); ++kj) + { + ClassType type2 = adj_elem[kj].first->instanceType(); + if (type2 != Class_Plane && type2 != Class_Cylinder) + continue; + if (type1 == Class_Cylinder && type2 == Class_Cylinder) + continue; + Point dir2 = adj_elem[kj].first->direction(); + if (type2 == Class_Plane && + dir2*adj_elem[kj].second->getMeanNormalTriang() < 0.0) + dir2 *= -1; + double ang = dir1.angle(dir2); + ang = std::min(ang, M_PI-ang); + bool compute_edge = false; +#ifdef DEBUG_BLEND + std::ofstream of("adj_reg.g2"); + adj_elem[ki].second->writeRegionPoints(of); + adj_elem[ki].second->writeSurface(of); + adj_elem[kj].second->writeRegionPoints(of); + adj_elem[kj].second->writeSurface(of); +#endif + if (type1 == Class_Plane && type2 == Class_Plane) + { + if (ang > blendfac*angtol) + compute_edge = true; + } + else + { + if (ang < blendfac*angtol) + compute_edge = true; + } + + if (compute_edge) + { + // Check if the two regions already has a common edge + vector<RevEngEdge*> edges1 = adj_elem[ki].second->getAllRevEdges(); + vector<RevEngEdge*> edges2 = adj_elem[kj].second->getAllRevEdges(); + size_t kr, kh; + for (kr=0; kr<edges1.size(); ++kr) + { + for (kh=0; kh<edges2.size(); ++kh) + if (edges1[kr] == edges2[kh]) + break; + if (kh < edges2.size()) + break; + } + + if (kr < edges1.size()) + { + // An edge exist already. Extend + continue; // For the time being + } + else + { + // Define new edge + size_t ix1, ix2; + for (ix1=0; ix1<regions_.size(); ++ix1) + if (regions_[ix1].get() == adj_elem[ki].second) + break; + for (ix2=0; ix2<regions_.size(); ++ix2) + if (regions_[ix2].get() == adj_elem[kj].second) + break; + if (ix1 == regions_.size() || ix2 == regions_.size()) + continue; + + // Make sure that the adjacent surfaces is bounded + if (!adj_elem[ki].first->isBounded()) + regions_[ix1]->getSurface(0)->limitSurf(diag); + if (!adj_elem[kj].first->isBounded()) + regions_[ix2]->getSurface(0)->limitSurf(diag); + vector<shared_ptr<RevEngEdge> > edges = + defineEdgesBetween(ix1, adj_elem[ki].first, + dir1, ix2, adj_elem[kj].first, dir2); + if (edges.size() > 0) + { + edges_.insert(edges_.end(), edges.begin(), edges.end()); + return true; + } + } + } + } + } + return false; +} + +//=========================================================================== +vector<shared_ptr<RevEngEdge> > +RevEng::defineEdgesBetween(size_t ix1, shared_ptr<ElementarySurface>& surf1, + Point& dir1, size_t ix2, + shared_ptr<ElementarySurface>& surf2, Point& dir2, + bool only_curve, double lenlim0, bool check_common) +//=========================================================================== +{ + vector<shared_ptr<RevEngEdge> > edges; + if (regions_[ix1]->hasAssociatedBlend() || regions_[ix2]->hasAssociatedBlend()) + return edges; + if (((regions_[ix1]->getSurfaceFlag() == ACCURACY_POOR || + regions_[ix1]->getSurfaceFlag() == NOT_SET) && + (!regions_[ix1]->hasBlendEdge())) || + ((regions_[ix2]->getSurfaceFlag() == ACCURACY_POOR || + regions_[ix2]->getSurfaceFlag() == NOT_SET) && + (!regions_[ix2]->hasBlendEdge()))) + return edges; + + //double angtol = 5.0*anglim_; + double diag = bbox_.low().dist(bbox_.high()); + double blendlim = std::min(0.1*diag, 30.0*mean_edge_len_); + double maxwidth = std::max(blendlim, 0.1*diag); + double lenlim = 10.0*mean_edge_len_; //blendlim; + if (lenlim0 > 0.0) + lenlim= std::min(lenlim, lenlim0); + double int_tol = 1.0e-6; + //bool plane1 = (surf1->instanceType() == Class_Plane); + //bool plane2 = (surf2->instanceType() == Class_Plane); + bool adjacent = regions_[ix1]->isAdjacent(regions_[ix2].get()); + + shared_ptr<BoundedSurface> bd1, bd2; + vector<shared_ptr<CurveOnSurface> > int_cvs1, int_cvs2; + BoundedUtils::getSurfaceIntersections(surf1, surf2, int_tol_, + int_cvs1, bd1, + int_cvs2, bd2); + if (int_cvs1.size() == 0) + return edges; + + bool keep_length = (int_cvs1.size() == 1 && (regions_[ix1]->hasBlendEdge() || + regions_[ix2]->hasBlendEdge())); + + // Limit intersection curves to relevant intervals + if (!keep_length) + { + for (size_t kr=0; kr<int_cvs1.size(); ) + { + vector<shared_ptr<CurveOnSurface> > tmp_int1, tmp_int2; + tmp_int1.push_back(int_cvs1[kr]); + tmp_int2.push_back(int_cvs2[kr]); + vector<pair<double,double> > t1_t2, t3_t4; + bool OK1 = + regions_[ix1]->getCurveRestriction(tmp_int1, approx_tol_, + anglim_, t1_t2); + bool OK2 = + regions_[ix2]->getCurveRestriction(tmp_int2, approx_tol_, + anglim_, t3_t4); + + double t1 = std::max(t1_t2[0].first, t3_t4[0].first); + double t2 = std::min(t1_t2[0].second, t3_t4[0].second); + if (t2 > t1 && (t1 > int_cvs1[kr]->startparam() || + t2 < int_cvs1[kr]->endparam())) + { + double pmin = std::max(t1, int_cvs1[kr]->startparam()); + double pmax = std::min(t2, int_cvs1[kr]->endparam()); + shared_ptr<CurveOnSurface> sub1(int_cvs1[kr]->subCurve(pmin,pmax)); + int_cvs1[kr] = sub1; + shared_ptr<CurveOnSurface> sub2(int_cvs2[kr]->subCurve(pmin,pmax)); + int_cvs2[kr] = sub2; + } + + if (t2 <= t1 || int_cvs1[kr]->estimatedCurveLength() < lenlim) + { + int_cvs1.erase(int_cvs1.begin()+kr); + int_cvs2.erase(int_cvs2.begin()+kr); + } + else + ++kr; + } + if (int_cvs1.size() == 0) + return edges; + } + + vector<RevEngRegion*> common_reg = + regions_[ix1]->commonAdjacent(regions_[ix2].get()); + for (size_t kj=0; kj<common_reg.size(); ) + { + if (common_reg[kj]->hasAssociatedBlend() || common_reg[kj]->hasBlendEdge()) + common_reg.erase(common_reg.begin()+kj); + else + ++kj; + } + + if (!adjacent && check_common) + { + // Check if any of the regions between is more significant + int num1 = regions_[ix1]->numPoints(); + int num2 = regions_[ix2]->numPoints(); + int fac = 2; + for (size_t kj=0; kj<common_reg.size(); ++kj) + { + if (!common_reg[kj]->hasSurface()) + continue; + int num3 = common_reg[kj]->numPoints(); + if (num3 > fac*std::min(num1, num2)) + return edges; // Could be a small passage. + } + } + +#ifdef DEBUG_EDGE + std::ofstream of1("adj_regs_cv.g2"); + for (size_t kr=0; kr<int_cvs1.size(); ++kr) + { + shared_ptr<ParamCurve> cv = int_cvs1[kr]->spaceCurve(); + cv->writeStandardHeader(of1); + cv->write(of1); + } + + if (common_reg.size() > 0) + { + std::ofstream of2("between_regs.g2"); + for (size_t kr=0; kr<common_reg.size(); ++kr) + { + common_reg[kr]->writeRegionPoints(of2); + if (common_reg[kr]->hasSurface()) + common_reg[kr]->writeSurface(of2); + } + } +#endif + + vector<RevEngRegion*> regs1; + regs1.push_back(regions_[ix2].get()); + regs1.insert(regs1.end(), common_reg.begin(), common_reg.end()); + vector<RevEngPoint*> bd_pts1 = + regions_[ix1]->extractBdPoints(); //regs1); + + vector<RevEngRegion*> regs2; + regs2.push_back(regions_[ix1].get()); + regs2.insert(regs2.end(), common_reg.begin(), common_reg.end()); + vector<RevEngPoint*> bd_pts2 = + regions_[ix2]->extractBdPoints();//regs2); + if (bd_pts1.size() == 0 || bd_pts2.size() == 0) + return edges; + +#ifdef DEBUG_EDGE + std::ofstream of3("bd_pts.g2"); + of3 << "400 1 0 4 255 0 0 255" << std::endl; + of3 << bd_pts1.size() << std::endl; + for (size_t kr=0; kr<bd_pts1.size(); ++kr) + of3 << bd_pts1[kr]->getPoint() << std::endl; + of3 << "400 1 0 4 255 0 0 255" << std::endl; + of3 << bd_pts2.size() << std::endl; + for (size_t kr=0; kr<bd_pts2.size(); ++kr) + of3 << bd_pts2[kr]->getPoint() << std::endl; +#endif + + // if (int_cvs1.size() > 1) + // { + // // Ensure consistent curve parameterization. Sort + // vector<Point> startpt(int_cvs1.size()), endpt(int_cvs1.size()); + // for (size_t kr=0; kr<int_cvs1.size(); ++kr) + // { + // startpt[kr] = int_cvs1[kr]->ParamCurve::point(int_cvs1[kr]->startparam()); + // endpt[kr] = int_cvs1[kr]->ParamCurve::point(int_cvs1[kr]->endparam()); + // } + // int stop_breakp = 1; + // } + int num_in_lim1=0, num_in_lim2=0; + vector<double> width2; + vector<shared_ptr<CurveOnSurface> > cvs1, cvs2; + for (size_t kr=0; kr<int_cvs1.size(); ++kr) + { + vector<pair<double,double> > tmin_tmax; + vector<double> width; + vector<shared_ptr<CurveOnSurface> > tmp_int1, tmp_int2; + tmp_int1.push_back(int_cvs1[kr]); + tmp_int2.push_back(int_cvs2[kr]); + vector<pair<double, double> > t5_t6, t7_t8; + vector<double> wwd1, wwd2; + int numlim1, numlim2; + regions_[ix1]->estimateBlendDimensions(tmp_int1, bd_pts1, + approx_tol_, blendlim, + t5_t6, wwd1, numlim1); + + regions_[ix2]->estimateBlendDimensions(tmp_int2, bd_pts2, + approx_tol_, blendlim, + t7_t8, wwd2, numlim2); + if (t5_t6.size() == 0 || t7_t8.size() == 0) + continue; + num_in_lim1 += numlim1; + num_in_lim2 += numlim2; + + // Unify intersection curve limitations + if (keep_length) + { + tmin_tmax.push_back(std::make_pair(int_cvs1[kr]->startparam(), + int_cvs1[kr]->endparam())); + double wwd = 0.0; + double w1min = std::numeric_limits<double>::max(); + double w2min = std::numeric_limits<double>::max(); + for (size_t kh=0; kh<wwd1.size(); ++kh) + { + wwd += wwd1[kh]; + w1min = std::min(w1min, wwd1[kr]); + } + for (size_t kh=0; kh<wwd2.size(); ++kh) + { + wwd += wwd2[kh]; + w2min = std::min(w2min, wwd2[kh]); + } + wwd /= (double)(wwd1.size()+wwd2.size()); + wwd = std::max(wwd, std::max(w1min, w2min)); + width.push_back(wwd); + } + else + { + size_t kk1, kk2; + for (kk1=0, kk2=0; kk1<wwd1.size() && kk2<wwd2.size(); ) + { + for (; kk1<wwd1.size() && t7_t8[kk2].first >= t5_t6[kk1].second; ++kk1); + if (kk1 == wwd1.size()) + break; + for (; kk2<wwd2.size() && t5_t6[kk1].first >= t7_t8[kk2].second; ++kk2); + tmin_tmax.push_back(std::make_pair(std::max(t5_t6[kk1].first,t7_t8[kk2].first), + std::min(t5_t6[kk1].second,t7_t8[kk2].second))); + width.push_back(0.5*(wwd1[kk1]+wwd2[kk2])); + if (t5_t6[kk1].second < t7_t8[kk2].second) + ++kk1; + else if (t7_t8[kk2].second < t5_t6[kk1].second) + ++kk2; + else + { + ++kk1; + ++kk2; + } + } + } + + size_t ki; + for (ki=0; ki<width.size(); ++ki) + { + double tmin = tmin_tmax[ki].first; + double tmax = tmin_tmax[ki].second; + double width3 = width[ki]; + if (tmax <= tmin+int_tol || width3 > maxwidth) + continue; + + double tp1 = std::max(int_cvs1[kr]->startparam(), tmin); + double tp2 = std::min(int_cvs1[kr]->endparam(), tmax); + if (tp2 <= tp1+int_tol) + continue; + if (tp1 > int_cvs1[kr]->startparam()+int_tol || + tp2 < int_cvs1[kr]->endparam()-int_tol) + { + shared_ptr<CurveOnSurface> sub1(int_cvs1[kr]->subCurve(tp1, tp2)); + shared_ptr<CurveOnSurface> sub2(int_cvs2[kr]->subCurve(tp1, tp2)); + cvs1.push_back(sub1); + cvs2.push_back(sub2); + } + else if (fabs(tp1-int_cvs1[kr]->startparam()) < int_tol && + fabs(tp2-int_cvs1[kr]->endparam()) < int_tol) + { + cvs1.push_back(int_cvs1[kr]); + cvs2.push_back(int_cvs2[kr]); + } + width2.push_back(width3); + } + } + + if (width2.size() == 0) + return edges; + if (num_in_lim1 == 0 || num_in_lim2 == 0) + return edges; + if (cvs1.size() == 0) + return edges; + +#ifdef DEBUG_EDGE + std::ofstream of1e("one_edgcv.g2"); + for (size_t kr=0; kr<cvs1.size(); ++kr) + { + cvs1[kr]->spaceCurve()->writeStandardHeader(of1e); + cvs1[kr]->spaceCurve()->write(of1e); + } +#endif + for (size_t kj=0; kj<cvs1.size(); ++kj) + { + shared_ptr<RevEngEdge> edg = defineOneEdge(ix1, surf1, dir1, ix2, + surf2, dir2, cvs1[kj], + cvs2[kj], width2[kj], + common_reg, only_curve, + check_common); + if (edg.get()) + edges.push_back(edg); + } + + return edges; +} + + +//=========================================================================== +shared_ptr<RevEngEdge> +RevEng::defineOneEdge(size_t ix1, shared_ptr<ElementarySurface>& surf1, + Point& dir1, size_t ix2, + shared_ptr<ElementarySurface>& surf2, Point& dir2, + shared_ptr<CurveOnSurface>& int_cv1, + shared_ptr<CurveOnSurface>& int_cv2, + double width, vector<RevEngRegion*>& common_reg, + bool only_curve, bool check_common) +//=========================================================================== +{ + shared_ptr<RevEngEdge> dummy_edg; + bool plane1 = (surf1->instanceType() == Class_Plane); + bool plane2 = (surf2->instanceType() == Class_Plane); + double angtol = 5.0*anglim_; + double tol10 = 10.0*approx_tol_; + int min_pt_blend = 20; + + if (plane1) + { + // Make sure that the plane normal poins out + Point avnorm = regions_[ix1]->getMeanNormal(); + if (dir1*avnorm < 0.0) + dir1 *= -1; + } + if (plane2) + { + // Make sure that the plane normal poins out + Point avnorm = regions_[ix2]->getMeanNormal(); + if (dir2*avnorm < 0.0) + dir2 *= -1; + } + int state = (plane1 || plane2) ? 1 : 2; + + + vector<vector<RevEngPoint*> > near_pts(common_reg.size()+2); + vector<RevEngPoint*> curr_near1, curr_near2; + double tmin1 = int_cv1->startparam(); + double tmax1 = int_cv1->endparam(); + if (!only_curve) + regions_[ix1]->getNearPoints(int_cv1, tmin1, tmax1, width, + angtol, curr_near1); + double tmin2 = int_cv2->startparam(); + double tmax2 = int_cv2->endparam(); + if (!only_curve) + regions_[ix2]->getNearPoints(int_cv2, tmin2, tmax2, width, + angtol, curr_near2); + if (curr_near1.size() == 0 && curr_near2.size() == 0 && (!only_curve)) + return dummy_edg; + + RevEngPoint *distant1 = 0, *distant2 = 0; + vector<RevEngPoint*> reg1_pts, reg2_pts; + if (only_curve) + { + reg1_pts = regions_[ix1]->getPoints(); + reg2_pts = regions_[ix2]->getPoints(); + } + distant1 = getDistantPoint(int_cv1, std::max(tmin1, tmin2), + std::min(tmax1, tmax2), approx_tol_, + width, (curr_near1.size() > 0) ? curr_near1 : + reg1_pts); + distant2 = getDistantPoint(int_cv2, std::max(tmin1, tmin2), + std::min(tmax1, tmax2), approx_tol_, + width, (curr_near2.size() > 0) ? curr_near2 : + reg2_pts); + if (!distant1) + { + Point mid; + int_cv1->point(mid, 0.5*(int_cv1->startparam()+int_cv1->endparam())); + double distmid; + distant1 = regions_[ix1]->closestPoint(mid, distmid); + } + if (!distant2) + { + Point mid; + int_cv2->point(mid, 0.5*(int_cv2->startparam()+int_cv2->endparam())); + double distmid; + distant2 = regions_[ix2]->closestPoint(mid, distmid); + } + if ((!distant1) || (!distant2)) + return dummy_edg; + + vector<Point> der(2); + Vector3D xyz1 = distant1->getPoint(); + Vector3D xyz2 = distant2->getPoint(); + Point loc1(xyz1[0], xyz1[1], xyz1[2]); + Point loc2(xyz2[0], xyz2[1], xyz2[2]); + Point distpt = (plane1) ? loc1 : loc2; + double dist; + double tpar; + Point close; + int_cv1->closestPoint(distpt, int_cv1->startparam(), + int_cv1->endparam(), tpar, close, dist); + int_cv1->point(der, tpar, 1); + + Point loc1_2 = loc1 - ((loc1-der[0])*der[1])*der[1]; + Point loc2_2 = loc2 - ((loc2-der[0])*der[1])*der[1]; + Point vec = loc1_2 - loc2_2; + bool outer1, outer2; + Point pos2; + if (plane1) + outer1 = (dir1*vec < 0.0); + else if (plane2) + { + // Cylinder or cone combined with plane + Point pos = surf1->location(); + double vval = (der[0]-pos)*dir1; + double rad = surf1->radius(0.0,vval); + pos2 = pos + vval*dir1; + Point loc2_3 = loc2 - ((loc2-der[0])*dir1)*dir1; + outer1 = (pos2.dist(loc2_3) < rad); + } + else if (surf1->instanceType() == Class_Cylinder) + { + // Cylinder combined with cone + Point axs = surf1->direction(); + Point tmp = loc1 + ((der[0]-loc1)*axs)*axs; + Point vec2 = loc1 - tmp; + Vector2D uv = distant2->getPar(); + double rad1 = surf2->radius(0.0, uv[1]); + double rad2 = surf1->radius(0.0, 0.0); + outer1 = (rad1 >= rad2); + if (vec2*axs < 0.0) + outer1 = (!outer1); + } + else + { + // Cone combined with cylinder + Vector2D uv = distant1->getPar(); + double rad1 = surf1->radius(0.0, uv[1]); + double rad2 = surf2->radius(0.0, 0.0); + outer1 = (rad1 >= rad2); + } + + if (plane2) + outer2 = (dir2*vec > 0.0); + else if (plane1) + { + Point pos = surf2->location(); + double vval = (der[0]-pos)*dir2; + double rad = surf2->radius(0.0,vval); + pos2 = pos + vval*dir2; + Point loc1_3 = loc1 - ((loc1-der[0])*dir2)*dir2; + outer2 = (pos2.dist(loc1_3) < rad); + } + else if (surf2->instanceType() == Class_Cylinder) + { + // Cylinder combined with cone + Vector2D uv = distant1->getPar(); + double rad1 = surf1->radius(0.0, uv[1]); + double rad2 = surf2->radius(0.0, 0.0); + Point axs = surf2->direction(); + Point tmp = loc2 + ((der[0]-loc2)*axs)*axs; + Point vec2 = loc2 - tmp; + outer2 = (rad1 >= rad2); + if (vec2*axs < 0.0) + outer2 = (!outer2); + } + else + { + // Cone combined with cylinder + Vector2D uv = distant2->getPar(); + double rad1 = surf2->radius(0.0, uv[1]); + double rad2 = surf1->radius(0.0, 0.0); + outer2 = (rad1 >= rad2); + } + + double mindist1=0.0, mindist2=0.0; + near_pts[0] = (curr_near1.size() == 0 || state == 2) ? curr_near1 : + regions_[ix2]->removeOutOfSurf(curr_near1, tol10, + angtol, outer2, mindist1); + near_pts[1] = (curr_near2.size() == 0 || state == 2) ? curr_near2 : + regions_[ix1]->removeOutOfSurf(curr_near2, tol10, + angtol, outer1, mindist2); + + if ((near_pts[0].size() == 0 || near_pts[1].size() == 0) && (!only_curve)) + return dummy_edg; + int nmb_near = (int)(near_pts[0].size() + near_pts[1].size()); + for (size_t kr=0; kr<common_reg.size(); ++kr) + { + vector<RevEngPoint*> adj_near1, adj_near2; + double dummy_min = 0.0; + double tmin3 = int_cv1->startparam(); + double tmax3 = int_cv1->endparam(); + common_reg[kr]->getNearPoints(int_cv1, tmin3, tmax3, width, + angtol, adj_near1); + if (state == 1) + { + adj_near2 = + regions_[ix1]->removeOutOfSurf(adj_near1, tol10, + angtol, outer1, dummy_min); + near_pts[2+kr] = + regions_[ix2]->removeOutOfSurf(adj_near2, tol10, + angtol, outer2, dummy_min); + } + else + near_pts[2+kr] = adj_near1; + + nmb_near += (int)near_pts[2+kr].size(); + } + if (nmb_near < min_pt_blend && (!only_curve)) + return dummy_edg; + +#ifdef DEBUG_EDGE + std::ofstream of4("blend_pts.g2"); + for (size_t kr=0; kr<near_pts.size(); ++kr) + { + of4 << "400 1 0 0" << std::endl; + of4 << near_pts[kr].size() << std::endl; + for (size_t kh=0; kh<near_pts[kr].size(); ++kh) + of4 << near_pts[kr][kh]->getPoint() << std::endl; + } +#endif + + // Ensure connection between adjacent regions + bool adjacent = only_curve ? true : false; + bool connection = false; + for (size_t kr=0; kr<near_pts[0].size(); ++kr) + { + for (size_t kh=0; kh<near_pts[1].size(); ++kh) + if (near_pts[0][kr]->isNeighbour(near_pts[1][kh])) + { + adjacent = true; + break; + } + if (adjacent) + break; + } + + for (size_t kr=2; kr<near_pts.size(); ++kr) + { + bool con1 = false, con2 = false; + for (size_t kh=0; kh<near_pts[kr].size(); ++kh) + { + if (kh != 0 && near_pts[kr][kh]->nextToRegion(regions_[ix1].get())) + con1 = true; + if (kh != 1 && near_pts[kr][kh]->nextToRegion(regions_[ix2].get())) + con2 = true; + if (con1 && con2) + { + connection = true; + break; + } + } + if (connection) + break; + } + if ((!connection) && (!adjacent) && (!regions_[ix1]->hasBlendEdge()) && + (!regions_[ix2]->hasBlendEdge())) + return dummy_edg; + + vector<pair<vector<RevEngPoint*>::iterator, + vector<RevEngPoint*>::iterator> > blend_groups; + for (size_t kr=0; kr<near_pts.size(); ++kr) + blend_groups.push_back(std::make_pair(near_pts[kr].begin(), + near_pts[kr].end())); + double radius = 0.0, ylen = 0.0; + if (!only_curve) + { + if (plane1 && plane2) + { + Point lin1 = der[1].cross(dir1); + Point lin2 = der[1].cross(dir2); + lin1.normalize(); + if (lin1*dir2 < 0.0) + lin1 *= -1; + lin2.normalize(); + if (lin2*dir1 < 0.0) + lin2 *= -1; + radius = computeCylinderRadius(near_pts, width, der[0], + der[1], lin1, lin2); + Point vec = lin1 + lin2; + vec.normalize(); + double alpha = lin1.angle(lin2); + double fac = 1.0/sin(0.5*alpha); + Point centre = der[0] - fac*radius*vec; + //double ang = lin1.angle(lin2); + double xlen = der[0].dist(centre); + ylen = sqrt(xlen*xlen - radius*radius); + } + else + { + int sgn = 1; + if ((plane1 && surf1->direction()*dir1 < 0.0) || + (plane2 && surf2->direction()*dir2 < 0.0)) + sgn = -1; + double d2 = 0.0; + radius = computeTorusRadius(near_pts, int_cv1, surf1, surf2, + width, outer1, outer2, sgn, d2); + + + Point centre, normal, Cx; + double Rrad; + bool OK = getTorusParameters(surf1, surf2, der[0], radius, d2, outer1, + outer2, sgn, Rrad, centre, normal, Cx, + check_common); + if (!OK) + return dummy_edg; + double xlen = der[0].dist(centre); + ylen = fabs(xlen - Rrad); + } + ylen *= 1.5; // Allow some slack + ylen= std::max(ylen, 1.1*std::max(mindist1, mindist2)); + + + // Reduce near points from adjacent groups according to the updated width + if (ylen < width) + { + for (size_t kr=2; kr<near_pts.size(); ++kr) + { + vector<RevEngPoint*> near_pts2; + common_reg[kr-2]->getNearPoints2(near_pts[kr], int_cv1, ylen, near_pts2); + std::swap(near_pts[kr], near_pts2); + } + } + } + +#ifdef DEBUG_EDGE + std::ofstream of5("blend_pts2.g2"); + for (size_t kr=0; kr<near_pts.size(); ++kr) + { + of5 << "400 1 0 0" << std::endl; + of5 << near_pts[kr].size() << std::endl; + for (size_t kh=0; kh<near_pts[kr].size(); ++kh) + of5 << near_pts[kr][kh]->getPoint() << std::endl; + } +#endif + + // An intersection/blend curve is found + // Segment identified adjacent groups according to curve + vector<RevEngRegion*> adj_regs; + vector<size_t> remove_ix; + for (size_t kr=0; kr<common_reg.size(); ++kr) + { + if (near_pts[kr+2].size() == 0) + continue; + + if ((int)near_pts[kr+2].size() < common_reg[kr]->numPoints()) + { + int num_init = common_reg[kr]->numPoints(); + vector<vector<RevEngPoint*> > out_groups; + vector<HedgeSurface*> out_sfs; + vector<vector<RevEngPoint*> > near_groups; + common_reg[kr]->extractSpesPoints(near_pts[kr+2], near_groups); + common_reg[kr]->updateInfo(); + common_reg[kr]->splitRegion(out_groups); + if (common_reg[kr]->hasSurface() && common_reg[kr]->numPoints() < num_init/2 && + !(common_reg[kr]->hasRevEdges() || common_reg[kr]->hasTrimEdges())) + { + int num_sf = common_reg[kr]->numSurface(); + for (int ka=0; ka<num_sf; ++ka) + out_sfs.push_back(common_reg[kr]->getSurface(ka)); + common_reg[kr]->clearSurface(); + } + + // Make new region + shared_ptr<RevEngRegion> curr_adj(new RevEngRegion(common_reg[kr]->getClassificationType(), + common_reg[kr]->getEdgeClassificationType(), + near_pts[kr+2])); + regions_.push_back(curr_adj); + adj_regs.push_back(curr_adj.get()); + + size_t kh=0; + for (kh=0; kh<regions_.size(); ++kh) + if (common_reg[kr] == regions_[kh].get()) + break; + surfaceExtractOutput((int)kh, out_groups, out_sfs); + } + else + { + adj_regs.push_back(common_reg[kr]); + remove_ix.push_back(kr); + } + } + + for (int ka=(int)remove_ix.size()-1; ka>=0; --ka) + common_reg.erase(common_reg.begin() + remove_ix[ka]); + + for (size_t kr=0; kr<adj_regs.size(); ++kr) + { + vector<vector<RevEngPoint*> > curr_out; + vector<HedgeSurface*> dummy_surfs; + adj_regs[kr]->splitRegion(curr_out); + if (curr_out.size() > 0) + { + size_t kh=0; + for (kh=0; kh<regions_.size(); ++kh) + if (adj_regs[kr] == regions_[kh].get()) + break; + surfaceExtractOutput((int)kh, curr_out, dummy_surfs); + } + } + + for (size_t kr=0; kr<adj_regs.size(); ++kr) + adj_regs[kr]->updateRegionAdjacency(); + regions_[ix1]->updateRegionAdjacency(); + regions_[ix2]->updateRegionAdjacency(); + + int edge_type = (only_curve) ? NOT_BLEND : BLEND_NOT_SET; + vector<shared_ptr<CurveOnSurface> > int_cvs1(1, int_cv1); + vector<shared_ptr<CurveOnSurface> > int_cvs2(1, int_cv2); + shared_ptr<RevEngEdge> edge(new RevEngEdge(edge_type, regions_[ix1].get(), + int_cvs1, outer1, regions_[ix2].get(), + int_cvs2, outer2, radius, + std::min(width, ylen))); + regions_[ix1]->addRevEdge(edge.get()); + regions_[ix2]->addRevEdge(edge.get()); + if (adj_regs.size() > 0) + edge->addBlendRegions(adj_regs); + for (size_t kr=0; kr<adj_regs.size(); ++kr) + adj_regs[kr]->setAssociatedBlend(edge.get()); + + return edge; +} + + +//=========================================================================== +RevEngPoint* RevEng::getDistantPoint(shared_ptr<CurveOnSurface>& cv, + double tmin, double tmax, double dd, + double width, vector<RevEngPoint*>& points) +//=========================================================================== +{ + RevEngPoint *distant = 0; + double ptdist = 0.0; + double eps = 1.0e-9; + for (size_t ki=0; ki<points.size(); ++ki) + { + if (points[ki]->getSurfaceDist() > dd) + continue; + + double tpar, dist; + Point close; + Vector3D xyz = points[ki]->getPoint(); + Point pt(xyz[0], xyz[1], xyz[2]); + cv->closestPoint(pt, cv->startparam(), cv->endparam(), + tpar, close, dist); + if (tpar > tmin+eps && tpar < tmax-eps && dist > ptdist && + dist < width) + { + ptdist = dist; + distant = points[ki]; + } + } + return distant; +} + + + +//=========================================================================== +void RevEng::computeAxisFromCylinder(Point initaxis[3], int min_num, double max_ang, + Point axis[3], int num_points[3]) +//=========================================================================== +{ + vector<vector<pair<std::vector<RevEngPoint*>::iterator, + std::vector<RevEngPoint*>::iterator> > > points(3); + num_points[0] = num_points[1] = num_points[2] = 0; + for (int ka=0; ka<3; ++ka) + axis[ka] = initaxis[ka]; + + Point axis0[3]; + for (int ka=0; ka<3; ++ka) + axis0[ka] = initaxis[ka]; + double max_ang2 = 0.5*M_PI - 1.0e-9; + for (int kc=0; kc<2; ++kc) + { + Point dummy(0.0, 0.0, 0.0); + vector<double> min_angle(3, max_ang2); + vector<Point> min_axis(3, dummy); + + for (size_t ki=0; ki<surfaces_.size(); ++ki) + { + int sfcode; + ClassType type = surfaces_[ki]->instanceType(sfcode); + if ((type != Class_Cylinder) && (type != Class_Cone)) + continue; + + shared_ptr<ElementarySurface> curr = + dynamic_pointer_cast<ElementarySurface,ParamSurface>(surfaces_[ki]->surface()); + if (!curr.get()) + continue; + + int num_reg = surfaces_[ki]->numRegions(); + if (num_reg == 0) + continue; // Should not happen + + RevEngRegion *reg0 = surfaces_[ki]->getRegion(0); + if (reg0->hasBlendEdge()) + continue; // Derived information + + if (reg0->hasAssociatedBlend()) + continue; // Outdated information + + int num_pts = surfaces_[ki]->numPoints(); + if (num_pts < min_num) + continue; + + Point vec = curr->direction(); + int ix = -1; + double min_angle0 = std::numeric_limits<double>::max(); + for (int ka=0; ka<3; ++ka) + { + double ang = vec.angle(axis0[ka]); + ang = std::min(ang, M_PI-ang); + if (ang < min_angle0) + { + min_angle0 = ang; + ix = ka; + } + if (ang < max_ang) + { + for (int kb=0; kb<num_reg; ++kb) + { + RevEngRegion *reg = surfaces_[ki]->getRegion(kb); + points[ka].push_back(std::make_pair(reg->pointsBegin(), + reg->pointsEnd())); + } + num_points[ka] += num_pts; + } + } + if (ix >= 0) + { + min_angle[ix] = min_angle0; + min_axis[ix] = vec; + } + } + if (num_points[0]+num_points[1]+num_points[2] == 0 && kc == 0) + { + for (int kb=0; kb<3; ++kb) + if (min_axis[kb].length() > 0.0) + axis0[kb] = min_axis[kb]; + } + else if (kc == 0) + break; + } + + Point Cx, Cy; + for (int ka=0; ka<3; ++ka) + { + if (points[ka].size() > 0) + { + RevEngUtils::computeAxis(points[ka], axis[ka], Cx, Cy); + } + else + axis[ka] = initaxis[ka]; + } + +} + +//=========================================================================== +void RevEng::computeAxisFromPlane(Point initaxis[3], int min_num, double max_ang, + Point axis[3], int num_points[3]) +//=========================================================================== +{ + vector<vector<shared_ptr<Plane> > > planes(3); + vector<vector<int> > num(3); + vector<vector<double> > avd(3); + num_points[0] = num_points[1] = num_points[2] = 0; + Point axis0[3]; + for (int ka=0; ka<3; ++ka) + axis0[ka] = initaxis[ka]; + double max_ang2 = 0.5*M_PI - 1.0e-9; + for (int kc=0; kc<2; ++kc) + { + Point dummy(0.0, 0.0, 0.0); + vector<double> min_angle(3, max_ang2); + vector<Point> min_axis(3, dummy); + for (size_t ki=0; ki<surfaces_.size(); ++ki) + { + int sfcode; + ClassType type = surfaces_[ki]->instanceType(sfcode); + if (type != Class_Plane) + continue; + + shared_ptr<Plane> curr = + dynamic_pointer_cast<Plane,ParamSurface>(surfaces_[ki]->surface()); + if (!curr.get()) + continue; + + int num_pts = surfaces_[ki]->numPoints(); + if (num_pts < min_num) + continue; + + // Check for a more accurate base surface + double avdist = 0.0; + int num_reg = surfaces_[ki]->numRegions(); + double fac = 1.0/(double)num_pts; + if (num_reg > 0) + { + // Should always be the case + RevEngRegion* reg = surfaces_[ki]->getRegion(0); + shared_ptr<ParamSurface> base = reg->getBase(); + if (base.get() && base->instanceType() == Class_Plane) + { + double av1 = 0.0, av2 = 0.0; + //int nmb = 0; + for (int ka=0; ka<num_reg; ++ka) + { + reg = surfaces_[ki]->getRegion(ka); + double maxds, avds, maxdb, avdb; + int num_in, num2_in, num_inb, num2_inb; + reg->getAccuracy(maxds, avds, num_in, num2_in); + reg->getBaseDist(maxdb, avdb, num_inb, num2_inb); + int nn = reg->numPoints(); + av1 += (double)nn*fac*avds; + av2 += (double)nn*fac*avdb; + } + if (av2 < av1) + { + curr = dynamic_pointer_cast<Plane,ParamSurface>(base); + avdist = av2; + } + else + avdist = av1; + } + } + + Point normal = curr->direction(); + int ix = -1; + double min_angle0 = std::numeric_limits<double>::max(); + for (int kb=0; kb<3; ++kb) + { + double ang = normal.angle(axis0[kb]); + ang = std::min(ang, M_PI-ang); + if (ang < min_angle0) + { + min_angle0 = ang; + ix = kb; + } + if (ang <= max_ang) + { + planes[kb].push_back(curr); + num[kb].push_back(num_pts); + avd[kb].push_back(avdist); + num_points[kb] += num_pts; + } + } + if (ix >= 0) + { + min_angle[ix] = min_angle0; + min_axis[ix] = normal; + } + } + if (num_points[0]+num_points[1]+num_points[2] == 0 && kc == 0) + { + for (int kb=0; kb<3; ++kb) + if (min_axis[kb].length() > 0.0) + axis0[kb] = min_axis[kb]; + } + else if (kc == 0) + break; + } + + for (int kb=0; kb<3; ++kb) + { + if (planes[kb].size() == 0) + { + axis[kb] = initaxis[kb]; + continue; + } + + axis[kb] = Point(0.0, 0.0, 0.0); + double fac = 1.0/(double)num_points[kb]; + for (size_t ki=0; ki<planes[kb].size(); ++ki) + { + Point normal = planes[kb][ki]->direction(); + if (normal*axis0[kb] < 0.0) + normal *= -1.0; + + double wgt = fac*(1.0 - avd[kb][ki])*num[kb][ki]; + wgt = std::max(wgt, 0.0); + axis[kb] += wgt*normal; + } + axis[kb].normalize_checked(); + } +} + +//=========================================================================== +bool RevEng::recognizeOneSurface(int& ix, int min_point_in, double angtol, + int pass) +//=========================================================================== +{ + bool firstpass = (pass <= 2); + if (regions_[ix]->tryOtherSurf(prefer_elementary_, firstpass) /*&& + regions_[ix]->feasiblePlane(zero_H_, zero_K_)*/) + { + vector<shared_ptr<HedgeSurface> > plane_sfs; + vector<HedgeSurface*> prev_surfs; + vector<vector<RevEngPoint*> > out_groups; + bool found = regions_[ix]->extractPlane(mainaxis_, + approx_tol_, min_point_in, + min_point_region_, angtol, + prefer_elementary_, + plane_sfs, prev_surfs, out_groups); + + if (out_groups.size() > 0 || prev_surfs.size() > 0) + surfaceExtractOutput(ix, out_groups, prev_surfs); + + if (plane_sfs.size() > 0) + surfaces_.insert(surfaces_.end(), plane_sfs.begin(), plane_sfs.end()); + if (found && regions_[ix]->getMaxSfDist() < 0.5*approx_tol_) + return true; // Result accepted + } + + if (regions_[ix]->tryOtherSurf(prefer_elementary_, firstpass)) + { + vector<shared_ptr<HedgeSurface> > cyl_sfs; + vector<HedgeSurface*> prev_surfs; + vector<vector<RevEngPoint*> > out_groups; + bool repeat = false; + + // Cylinder from context information + bool found = + regions_[ix]->contextCylinder(mainaxis_, approx_tol_, + min_point_in, min_point_region_, + angtol, prefer_elementary_, + cyl_sfs, prev_surfs, + out_groups); + + if (found == false && regions_[ix]->feasibleCylinder(zero_H_, zero_K_)) + (void)regions_[ix]->extractCylinder(approx_tol_, min_point_in, + min_point_region_, angtol, + prefer_elementary_, + cyl_sfs, prev_surfs, + out_groups, repeat); + + + if (out_groups.size() > 0 || prev_surfs.size() > 0) + surfaceExtractOutput(ix, out_groups, prev_surfs); + + if (repeat) + { + --ix; + return false; // New try + } + + + if (cyl_sfs.size() > 0) + surfaces_.insert(surfaces_.end(), cyl_sfs.begin(), cyl_sfs.end()); + if (found && regions_[ix]->getMaxSfDist() < 0.5*approx_tol_) + return true; + } + + if (regions_[ix]->tryOtherSurf(prefer_elementary_, firstpass) && (!firstpass) && + regions_[ix]->hasSweepInfo() && regions_[ix]->sweepType() == 1) + { + vector<shared_ptr<HedgeSurface> > linsweep_sfs; + vector<HedgeSurface*> prev_surfs; + vector<vector<RevEngPoint*> > out_groups; + bool found = regions_[ix]->extractLinearSweep(approx_tol_, min_point_in, + min_point_region_, angtol, + prefer_elementary_, + linsweep_sfs, + prev_surfs); + if (out_groups.size() > 0 || prev_surfs.size() > 0) + surfaceExtractOutput(ix, out_groups, prev_surfs); + + if (linsweep_sfs.size() > 0) + surfaces_.insert(surfaces_.end(), linsweep_sfs.begin(), linsweep_sfs.end()); + + if (found && regions_[ix]->getMaxSfDist() < 0.5*approx_tol_) + return true; + } + + if (regions_[ix]->tryOtherSurf(prefer_elementary_, firstpass) && pass > 1) + { + vector<shared_ptr<HedgeSurface> > tor_sfs; + vector<HedgeSurface*> prev_surfs; + vector<vector<RevEngPoint*> > out_groups; + + // Torus from context information + bool found = regions_[ix]->contextTorus(mainaxis_, approx_tol_, + min_point_in, min_point_region_, + angtol, prefer_elementary_, + tor_sfs, prev_surfs, + out_groups); + if (regions_[ix]->numPoints() == 0) + { + regions_.erase(regions_.begin()+ix); + --ix; + return false; + } + + if (!found) + found = regions_[ix]->extractTorus(mainaxis_, approx_tol_, min_point_in, + min_point_region_, + angtol, prefer_elementary_, + tor_sfs, prev_surfs, + out_groups); + + if (out_groups.size() > 0 || prev_surfs.size() > 0) + surfaceExtractOutput(ix, out_groups, prev_surfs); + + if (tor_sfs.size() > 0) + surfaces_.insert(surfaces_.end(), tor_sfs.begin(), tor_sfs.end()); + if (found && regions_[ix]->getMaxSfDist() < 0.5*approx_tol_) + return true; + } + + if (regions_[ix]->tryOtherSurf(prefer_elementary_, firstpass) && pass > 1) + { + vector<shared_ptr<HedgeSurface> > sph_sfs; + vector<HedgeSurface*> prev_surfs; + vector<vector<RevEngPoint*> > out_groups; + bool found = regions_[ix]->extractSphere(mainaxis_, approx_tol_, + min_point_in, min_point_region_, + angtol, prefer_elementary_, + sph_sfs, prev_surfs, + out_groups); + + + if (out_groups.size() > 0 || prev_surfs.size() > 0) + surfaceExtractOutput(ix, out_groups, prev_surfs); + + if (sph_sfs.size() > 0) + surfaces_.insert(surfaces_.end(), sph_sfs.begin(), sph_sfs.end()); + if (found && regions_[ix]->getMaxSfDist() < 0.5*approx_tol_) + return true; + } + + if (regions_[ix]->tryOtherSurf(prefer_elementary_, firstpass) && pass > 1) + { + vector<shared_ptr<HedgeSurface> > cone_sfs; + vector<HedgeSurface*> prev_surfs; + vector<vector<RevEngPoint*> > out_groups; + bool found = + regions_[ix]->extractCone(approx_tol_, min_point_in, min_point_region_, + angtol, prefer_elementary_, + cone_sfs, prev_surfs, + out_groups); + + if (out_groups.size() > 0 || prev_surfs.size() > 0) + surfaceExtractOutput(ix, out_groups, prev_surfs); + + if (cone_sfs.size() > 0) + surfaces_.insert(surfaces_.end(), cone_sfs.begin(), cone_sfs.end()); + if (found && regions_[ix]->getMaxSfDist() < 0.5*approx_tol_) + return true; + } + + if (regions_[ix]->tryOtherSurf(prefer_elementary_, firstpass) && (!firstpass)) + { + vector<shared_ptr<HedgeSurface> > spl_sfs; + vector<HedgeSurface*> prev_surfs; + vector<vector<RevEngPoint*> > out_groups; + bool found = + regions_[ix]->extractFreeform(approx_tol_, min_point_in, + min_point_region_, angtol, + prefer_elementary_, + spl_sfs, prev_surfs, + out_groups); + + if (out_groups.size() > 0 || prev_surfs.size() > 0) + surfaceExtractOutput(ix, out_groups, prev_surfs); + + if (spl_sfs.size() > 0) + surfaces_.insert(surfaces_.end(), spl_sfs.begin(), spl_sfs.end()); + } + + if (!regions_[ix]->hasSurface()) + { + vector<shared_ptr<HedgeSurface> > adj_sfs; + vector<HedgeSurface*> prev_surfs; + vector<vector<RevEngPoint*> > out_groups; + bool found = + regions_[ix]->adjacentToCylinder(mainaxis_, approx_tol_, min_point_in, + min_point_region_, angtol, + prefer_elementary_, + adj_sfs, prev_surfs, + out_groups); + + if (out_groups.size() > 0 || prev_surfs.size() > 0) + surfaceExtractOutput(ix, out_groups, prev_surfs); + + if (adj_sfs.size() > 0) + surfaces_.insert(surfaces_.end(), adj_sfs.begin(), adj_sfs.end()); + } +#ifdef DEBUG + if (regions_[ix]->hasSurface()) + { + std::ofstream of("one_surface.g2"); + regions_[ix]->writeSurface(of); + } +#endif + return (regions_[ix]->hasSurface()); +} + +//=========================================================================== +void RevEng::recognizeSurfaces(int min_point_in, int pass) +//=========================================================================== +{ + double angfac = 5.0; + double angtol = angfac*anglim_; + int pass2 = pass + 1; + std::sort(regions_.begin(), regions_.end(), sort_region); +#ifdef DEBUG + for (int ki=0; ki<(int)regions_.size(); ++ki) + { + std::set<RevEngPoint*> tmpset(regions_[ki]->pointsBegin(), regions_[ki]->pointsEnd()); + if ((int)tmpset.size() != regions_[ki]->numPoints()) + std::cout << "Point number mismatch, pre recognizeSurfaces. " << ki << " " << tmpset.size() << " " << regions_[ki]->numPoints() << std::endl; + int num = regions_[ki]->numPoints(); + for (int ka=0; ka<num; ++ka) + if (regions_[ki]->getPoint(ka)->region() != regions_[ki].get()) + std::cout << "Inconsistent region pointers, pre recognizeSurfaces: " << ki << " " << ka << std::endl; + } +#endif + + for (int ki=0; ki<(int)regions_.size(); ++ki) + { +#ifdef DEBUG_CHECK + std::set<RevEngPoint*> tmpset(regions_[ki]->pointsBegin(), regions_[ki]->pointsEnd()); + if ((int)tmpset.size() != regions_[ki]->numPoints()) + std::cout << "Point number mismatch, pre. " << ki << " " << tmpset.size() << " " << regions_[ki]->numPoints() << std::endl; + + #endif + } + for (int ki=0; ki<(int)regions_.size(); ++ki) + { +#ifdef DEBUG_CHECK + std::set<RevEngPoint*> tmpset(regions_[ki]->pointsBegin(), regions_[ki]->pointsEnd()); + if ((int)tmpset.size() != regions_[ki]->numPoints()) + std::cout << "Point number mismatch. " << ki << " " << tmpset.size() << " " << regions_[ki]->numPoints() << std::endl; + for (size_t kj=0; kj<regions_.size(); ++kj) + { + int nump = regions_[kj]->numPoints(); + for (int ka=0; ka<nump; ++ka) + if (regions_[kj]->getPoint(ka)->region() != regions_[kj].get()) + std::cout << "Inconsistent region pointers, recognizeSurfaces: " << ki << " " << kj << " " << ka << std::endl; + } +#endif + if (regions_[ki]->numPoints() < min_point_region_) + continue; + if (regions_[ki]->hasAssociatedBlend()) + continue; // Treated separately +#ifdef DEBUGONE + //int classtype = regions_[ki]->getClassification(); + //std::cout << "No " << ki << ", classtype: " << classtype << std::endl; + + std::ofstream of1("region.g2"); + regions_[ki]->writeRegionInfo(of1); + if (regions_[ki]->hasSurface()) + regions_[ki]->writeSurface(of1); + std::ofstream of2("unitsphere.g2"); + regions_[ki]->writeUnitSphereInfo(of2); +#endif + if (regions_[ki]->hasBlendEdge()) + continue; + if (regions_[ki]->hasRevEdges()) + continue; + if (regions_[ki]->getAdaptionHistory() > INITIAL) + continue; // Do not redo + + bool pot_blend = false; + if (!regions_[ki]->hasSurface()) + pot_blend = regions_[ki]->potentialBlend(angtol); + if (pot_blend) + { +#ifdef DEBUG + std::cout << "Potential blend" << std::endl; +#endif + bool done = setBlendEdge(ki); + if (done) + continue; + } + bool found = recognizeOneSurface(ki, min_point_in, angtol, pass2); +#ifdef DEBUG_CHECK + bool connect = regions_[ki]->isConnected(); + if (!connect) + std::cout << "recognizeOneSurface, disconnected region " << ki << std::endl; +#endif + +#ifdef DEBUG_CHECK + for (int kj=0; kj<(int)regions_.size(); ++kj) + { + std::set<RevEngPoint*> tmpset2(regions_[kj]->pointsBegin(), regions_[kj]->pointsEnd()); + if ((int)tmpset2.size() != regions_[kj]->numPoints()) + std::cout << "Point number mismatch 2. " << kj << " " << ki << " " << tmpset2.size() << " " << regions_[kj]->numPoints() << std::endl; + } +#endif + if ((!regions_[ki]->hasSurface()) || + (regions_[ki]->hasSurface() && + (regions_[ki]->getSurfaceFlag() == ACCURACY_POOR || + regions_[ki]->getSurfaceFlag() == NOT_SET))) + { + // Still no surface. Try to divide composite regions into smaller + // pieces + bool split = segmentComposite(ki, min_point_in, angtol); +#ifdef DEBUG_CHECK + if (ki >= 0) + { + bool connect = regions_[ki]->isConnected(); + if (!connect) + std::cout << "segmentComposite, disconnected region " << ki << std::endl; + } +#endif + int stop_split = 1; + } + } + +#ifdef DEBUG + for (int ki=0; ki<(int)regions_.size(); ++ki) + { + std::set<RevEngPoint*> tmpset(regions_[ki]->pointsBegin(), regions_[ki]->pointsEnd()); + if ((int)tmpset.size() != regions_[ki]->numPoints()) + std::cout << "Point number mismatch, post recognizeSurfaces. " << ki << " " << tmpset.size() << " " << regions_[ki]->numPoints() << std::endl; + int num = regions_[ki]->numPoints(); + for (int ka=0; ka<num; ++ka) + if (regions_[ki]->getPoint(ka)->region() != regions_[ki].get()) + std::cout << "Inconsistent region pointers, post recognizeSurfaces: " << ki << " " << ka << std::endl; + } +#endif + + // Update adjacency between regions + for (size_t ki=0; ki<regions_.size(); ++ki) + { + regions_[ki]->clearRegionAdjacency(); + } + for (size_t ki=0; ki<regions_.size(); ++ki) + { + regions_[ki]->setRegionAdjacency(); + } + +} + + +//=========================================================================== +bool RevEng::segmentComposite(int& ix, int min_point_in, double angtol) +//=========================================================================== +{ + // To be updated + double frac_norm_lim = 0.2; //0.75; + bool segmented = false; + + if (regions_[ix]->numPoints() < min_point_region_) + return false; + + if (regions_[ix]->hasSurface() && + (!(regions_[ix]->getSurfaceFlag() == ACCURACY_POOR || + regions_[ix]->getSurfaceFlag() == NOT_SET))) + return false; + + if (regions_[ix]->hasSweepInfo()) + return false; + +#ifdef DEBUG_DIV + std::cout << "Segment composite, ix=" << ix << std::endl; + std::ofstream ofs("region_to_segm.g2"); + regions_[ix]->writeRegionInfo(ofs); + std::ofstream of2("unitsphere_segm.g2"); + regions_[ix]->writeUnitSphereInfo(of2); + Point origo(0.0, 0.0, 0.0); + of2 << "410 1 0 4 0 0 0 255" << std::endl; + of2 << "3" << std::endl; + for (int ka=0; ka<3; ++ka) + of2 << origo << " " << mainaxis_[ka] << std::endl; + + std::ofstream ofa("adjacent_to_segm.g2"); + regions_[ix]->writeAdjacentPoints(ofa); + //regions_[ix]->sortByAxis(mainaxis_, min_point_in, approx_tol_); +#endif + + size_t num_points = regions_[ix]->numPoints(); + + bool plane_grow = false; + if (plane_grow && regions_[ix]->getFracNorm() > frac_norm_lim) + { + // Grow sub regions according to surface type +#ifdef DEBUG_DIV + //std::cout << "Grow planes" << std::endl; +#endif + segmented = segmentByPlaneGrow(ix, min_point_in, angtol); +#ifdef DEBUG_DIV + if (segmented) + std::cout << "Segmented by grow planes" << std::endl; +#endif + } + + bool repeat = false; + vector<shared_ptr<HedgeSurface> > hedgesfs; + vector<shared_ptr<RevEngRegion> > added_reg; + vector<vector<RevEngPoint*> > separate_groups; + vector<RevEngPoint*> single_points; + vector<HedgeSurface*> prevsfs; + + if (!segmented && regions_[ix]->hasDivideInfo()) + { + for (int ki=0; ki<regions_[ix]->numDivideInfo(); ++ki) + { + segmented = regions_[ix]->divideWithSegInfo(ki, + min_point_region_, + separate_groups, + single_points); + if (segmented) + break; + } + } + + if (!segmented) + { + // Check if a segmentation into several cylinder like + // regions is feasible + double avH, avK, MAH, MAK; + regions_[ix]->getAvCurvatureInfo(avH, avK, MAH, MAK); + double fac = 5.0; + if (MAH > fac*MAK) + { + segmented = regions_[ix]->extractCylByAxis(mainaxis_, min_point_in, + min_point_region_, + approx_tol_, angtol, + prefer_elementary_, + hedgesfs, added_reg, + separate_groups, + single_points); + } + } + +#ifdef DEBUG_CHECK + for (int ki=0; ki<(int)regions_.size(); ++ki) + { + std::set<RevEngPoint*> tmpset1(regions_[ki]->pointsBegin(), regions_[ki]->pointsEnd()); + if ((int)tmpset1.size() != regions_[ki]->numPoints()) + std::cout << "Point number mismatch, composite 1. " << ki << " " << tmpset1.size() << " " << regions_[ki]->numPoints() << std::endl; + } +#endif + + if (!segmented) + { + vector<RevEngRegion*> adj_planar = regions_[ix]->fetchAdjacentPlanar(); + if (adj_planar.size() > 1) + { + segmented = regions_[ix]->segmentByPlaneAxis(mainaxis_, min_point_in, + min_point_region_, + approx_tol_, angtol, + prefer_elementary_, + adj_planar, hedgesfs, + added_reg, + prevsfs, separate_groups); +#ifdef DEBUG_CHECK + for (int ki=0; ki<(int)regions_.size(); ++ki) + { + std::set<RevEngPoint*> tmpset2(regions_[ki]->pointsBegin(), regions_[ki]->pointsEnd()); + if ((int)tmpset2.size() != regions_[ki]->numPoints()) + std::cout << "Point number mismatch, composite 2. " << ki << " " << tmpset2.size() << " " << regions_[ki]->numPoints() << std::endl; + } + + for (size_t kr=0; kr<adj_planar.size(); ++kr) + { + std::set<RevEngPoint*> tmpset(adj_planar[kr]->pointsBegin(), + adj_planar[kr]->pointsEnd()); + if ((int)tmpset.size() != adj_planar[kr]->numPoints()) + std::cout << "Point number mismatch (ByPlaneAxis). " << kr << " " << tmpset.size() << " " << adj_planar[kr]->numPoints() << std::endl; + } + +#endif + } + + if (!segmented) + { + // Extend with cylindrical + vector<RevEngRegion*> adj_cyl = + regions_[ix]->fetchAdjacentCylindrical(); + if (adj_cyl.size() > 0) + adj_planar.insert(adj_planar.end(), adj_cyl.begin(), + adj_cyl.end()); + if (adj_planar.size() > 0) + segmented = + regions_[ix]->segmentByAdjSfContext(mainaxis_, min_point_in, + min_point_region_, + approx_tol_, angtol, + adj_planar, separate_groups); +#ifdef DEBUG_CHECK + for (int ki=0; ki<(int)regions_.size(); ++ki) + { + std::set<RevEngPoint*> tmpset4(regions_[ki]->pointsBegin(), regions_[ki]->pointsEnd()); + if ((int)tmpset4.size() != regions_[ki]->numPoints()) + std::cout << "Point number mismatch, composite 4. " << ki << " " << tmpset4.size() << " " << regions_[ki]->numPoints() << std::endl; + } + for (size_t kr=0; kr<adj_planar.size(); ++kr) + { + std::set<RevEngPoint*> tmpset(adj_planar[kr]->pointsBegin(), + adj_planar[kr]->pointsEnd()); + if ((int)tmpset.size() != adj_planar[kr]->numPoints()) + std::cout << "Point number mismatch (ByAdjSfContext). " << kr << " " << tmpset.size() << " " << adj_planar[kr]->numPoints() << std::endl; + } +#endif + } + } + + if (added_reg.size() > 0) + repeat = true; + else if (separate_groups.size() > 0) + { + int num = 0; + for (size_t ki=0; ki<separate_groups.size(); ++ki) + num += (int)separate_groups[ki].size(); + if (num > (int)num_points/10) + repeat = true; + } + +#ifdef DEBUG_CHECK + for (int ki=0; ki<(int)regions_.size(); ++ki) + { + std::set<RevEngPoint*> tmpset5(regions_[ki]->pointsBegin(), regions_[ki]->pointsEnd()); + if ((int)tmpset5.size() != regions_[ki]->numPoints()) + std::cout << "Point number mismatch, composite 5. " << ki << " " << tmpset5.size() << " " << regions_[ki]->numPoints() << std::endl; + } +#endif +#ifdef DEBUG + if (regions_[ix]->numPoints() < (int)num_points) + { + std::ofstream of("seg_by_context.g2"); + int num = regions_[ix]->numPoints(); + of << "400 1 0 4 255 0 0 255" << std::endl; + of << num << std::endl; + for (int ka=0; ka<num; ++ka) + of << regions_[ix]->getPoint(ka)->getPoint() << std::endl; + + for (size_t ki=0; ki<separate_groups.size(); ++ki) + { + of << "400 1 0 4 0 255 0 255" << std::endl; + of << separate_groups[ki].size() << std::endl; + for (int ka=0; ka<(int)separate_groups[ki].size(); ++ka) + of << separate_groups[ki][ka]->getPoint() << std::endl; + } + + for (size_t ki=0; ki<added_reg.size(); ++ki) + { + int num = added_reg[ki]->numPoints(); + of << "400 1 0 4 0 0 255 255" << std::endl; + of << num << std::endl; + for (int ka=0; ka<num; ++ka) + of << added_reg[ki]->getPoint(ka)->getPoint() << std::endl; + if (added_reg[ki]->hasSurface()) + added_reg[ki]->writeSurface(of); + } + } +#endif + + // Update adjacency information for current region + regions_[ix]->updateRegionAdjacency(); + +#ifdef DEBUG_CHECK + for (int ki=0; ki<(int)regions_.size(); ++ki) + { + std::set<RevEngPoint*> tmpset6(regions_[ki]->pointsBegin(), regions_[ki]->pointsEnd()); + if ((int)tmpset6.size() != regions_[ki]->numPoints()) + std::cout << "Point number mismatch, composite 6. " << ki << " " << tmpset6.size() << " " << regions_[ki]->numPoints() << std::endl; + } +#endif + if (added_reg.size() > 0 && regions_[ix]->hasSurface() == false) + { + // Swap sequence of regions + int max_pt = 0; + int max_ix = -1; + for (size_t ki=0; ki<added_reg.size(); ++ki) + if (added_reg[ki]->numPoints() > max_pt) + { + max_pt = added_reg[ki]->numPoints(); + max_ix = (int)ki; + } + if (max_ix >= 0) + std::swap(regions_[ix], added_reg[max_ix]); + } +#ifdef DEBUG_CHECK + for (int ki=0; ki<(int)regions_.size(); ++ki) + { + std::set<RevEngPoint*> tmpset6_2(regions_[ki]->pointsBegin(), regions_[ki]->pointsEnd()); + if ((int)tmpset6_2.size() != regions_[ki]->numPoints()) + std::cout << "Point number mismatch, composite 6_2. " << ki << " " << tmpset6_2.size() << " " << regions_[ki]->numPoints() << std::endl; + } +#endif + if (separate_groups.size() > 0) + { + vector<HedgeSurface*> prev_surfs; + surfaceExtractOutput(ix, separate_groups, prev_surfs); + } + +#ifdef DEBUG_CHECK + for (int ki=0; ki<(int)regions_.size(); ++ki) + { + std::set<RevEngPoint*> tmpset7(regions_[ki]->pointsBegin(), regions_[ki]->pointsEnd()); + if ((int)tmpset7.size() != regions_[ki]->numPoints()) + std::cout << "Point number mismatch, composite 7. " << ki << " " << tmpset7.size() << " " << regions_[ki]->numPoints() << std::endl; + } + if (!regions_[ix]->isConnected()) + std::cout << "Disconnected region (split), ix= " << ix << " " << regions_[ix].get() << std::endl; +#endif + if (added_reg.size() > 0) + regions_.insert(regions_.end(), added_reg.begin(), added_reg.end()); + if (hedgesfs.size() > 0) + surfaces_.insert(surfaces_.end(), hedgesfs.begin(), hedgesfs.end()); + if (repeat && (!regions_[ix]->hasSurface())) + { +#ifdef DEBUG_DIV + std::cout << "Repeat ix = " << ix << std::endl; +#endif + --ix; + } + + return segmented; +} + +//=========================================================================== +void RevEng::adjustPointRegions(int min_point_in) +//=========================================================================== +{ + double angfac = 5.0; + double angtol = angfac*anglim_; + for (size_t ki=0; ki<regions_.size(); ++ki) + { + if (regions_[ki]->hasSurface()) + continue; + if (regions_[ki]->hasAssociatedBlend()) + continue; + if (regions_[ki]->numPoints() < min_point_in) + continue; + + vector<pair<shared_ptr<ElementarySurface>, RevEngRegion*> > adj_elem, adj_elem_base; + regions_[ki]->getAdjacentElemInfo(adj_elem, adj_elem_base); + if (adj_elem.size() == 0) + continue; + + vector<RevEngRegion*> adj_groups(adj_elem.size()); + for (size_t kj=0; kj<adj_elem.size(); ++kj) + adj_groups[kj] = adj_elem[kj].second; + + vector<vector<RevEngPoint*> > out_groups; + (void)regions_[ki]->segmentByAdjSfContext(mainaxis_, min_point_in, + min_point_region_, + approx_tol_, + angtol, adj_groups, + out_groups); + if (regions_[ki]->numPoints() == 0) + { + vector<RevEngRegion*> adjacent; + regions_[ki]->getAdjacentRegions(adjacent); + for (size_t kj=0; kj<adjacent.size(); ++kj) + adjacent[kj]->removeAdjacentRegion(regions_[ki].get()); + + regions_.erase(regions_.begin()+ki); + --ki; + } + + if (out_groups.size() > 0) + { + vector<HedgeSurface*> dummy; + surfaceExtractOutput((int)ki, out_groups, dummy); + } + + } +} + +//=========================================================================== +void RevEng::surfaceCreation(int pass) +//=========================================================================== +{ + // Update adjacency between regions + for (size_t ki=0; ki<regions_.size(); ++ki) + { + regions_[ki]->clearRegionAdjacency(); + } + for (size_t ki=0; ki<regions_.size(); ++ki) + { + regions_[ki]->setRegionAdjacency(); + } + + int min_point_in = 50; //10; //20; + adjustPointRegions(min_point_in); + + // Update adjacency between regions + for (size_t ki=0; ki<regions_.size(); ++ki) + { + regions_[ki]->clearRegionAdjacency(); + } + for (size_t ki=0; ki<regions_.size(); ++ki) + { + regions_[ki]->setRegionAdjacency(); + } + + // First pass. Recognize elementary surfaces + recognizeSurfaces(min_point_in, pass); + +#ifdef DEBUG + checkConsistence("Regions9"); + + if (regions_.size() > 0) + { + std::cout << "Regions9" << std::endl; + std::ofstream of("regions9.g2"); + std::ofstream ofm("mid_regions9.g2"); + std::ofstream ofs("small_regions9.g2"); + writeRegionStage(of, ofm, ofs); + std::ofstream of0("regions9_helix.g2"); + for (int ki=0; ki<(int)regions_.size(); ++ki) + { + if (regions_[ki]->getSurfaceFlag() == PROBABLE_HELIX) + { + regions_[ki]->writeRegionInfo(of0); + if (regions_[ki]->hasSurface()) + regions_[ki]->writeSurface(of0); + } + } + if (surfaces_.size() > 0) + { + std::ofstream of("regsurf9.g2"); + writeRegionWithSurf(of); + } + + if (edges_.size() > 0) + { + std::ofstream ofe("edges9.g2"); + writeEdgeStage(ofe); + } + + std::cout << "Merge adjacent regions, regions: " << regions_.size() << ", surfaces: " << surfaces_.size() << std::endl; +#endif + double angtol = 5.0*anglim_; + for (int ki=0; ki<(int)regions_.size(); ++ki) + { + if (regions_[ki]->hasSurface()) + { + vector<RevEngRegion*> grown_regions; + vector<HedgeSurface*> adj_surfs; + vector<RevEngEdge*> adj_edgs; + regions_[ki]->mergeAdjacentSimilar(approx_tol_, angtol, + grown_regions, adj_surfs, adj_edgs); + if (grown_regions.size() > 0 || adj_surfs.size() > 0) + updateRegionsAndSurfaces(ki, grown_regions, adj_surfs); + for (size_t kr=0; kr<adj_edgs.size(); ++kr) + { + size_t kj; + for (kj=0; kj<edges_.size(); ++kj) + if (edges_[kj].get() == adj_edgs[kr]) + break; + if (kj < edges_.size()) + edges_.erase(edges_.begin()+kj); + } + } + } +#ifdef DEBUG + checkConsistence("Regions10"); + + std::cout << "Finished merge adjacent regions, regions: " << regions_.size() << ", surfaces: " << surfaces_.size() << std::endl; + if (regions_.size() > 0) + { + std::cout << "Regions10" << std::endl; + std::ofstream of("regions10.g2"); + std::ofstream ofm("mid_regions10.g2"); + std::ofstream ofs("small_regions10.g2"); + writeRegionStage(of, ofm, ofs); + std::ofstream of0("regions10_helix.g2"); + for (int ki=0; ki<(int)regions_.size(); ++ki) + { + if (regions_[ki]->getSurfaceFlag() == PROBABLE_HELIX) + { + regions_[ki]->writeRegionInfo(of0); + if (regions_[ki]->hasSurface()) + regions_[ki]->writeSurface(of0); + } + } + if (surfaces_.size() > 0) + { + std::ofstream of("regsurf10.g2"); + writeRegionWithSurf(of); + } + } + + if (edges_.size() > 0) + { + std::ofstream ofe("edges10.g2"); + writeEdgeStage(ofe); + } +#endif + // Update adjacency between regions + for (size_t ki=0; ki<regions_.size(); ++ki) + { + regions_[ki]->clearRegionAdjacency(); + } + for (size_t ki=0; ki<regions_.size(); ++ki) + { + regions_[ki]->setRegionAdjacency(); + } + +#ifdef DEBUG_CHECK + for (int ka=0; ka<(int)regions_.size(); ++ka) + { + std::set<RevEngPoint*> tmpset(regions_[ka]->pointsBegin(), regions_[ka]->pointsEnd()); + if ((int)tmpset.size() != regions_[ka]->numPoints()) + std::cout << "Point number mismatch, pre grow. " << ka << " " << tmpset.size() << " " << regions_[ka]->numPoints() << std::endl; + + bool con = regions_[ka]->isConnected(); + if (!con) + std::cout << "Disconnected region, ka= " << ka << " " << regions_[ka].get() << std::endl; + } +#endif + + for (int ki=0; ki<(int)regions_.size(); ++ki) + { + if (regions_[ki]->hasSurface() && regions_[ki]->getSurfaceFlag() < ACCURACY_POOR) + { +#ifdef DEBUG_GROW + std::cout << "ki=" << ki << ", nmb reg: " << regions_.size() << ", nmb surf: " << surfaces_.size() << std::endl; +#endif + growSurface(ki, pass); +#ifdef DEBUG_CHECK + if (!regions_[ki]->isConnected()) + std::cout << "Disconnected region (grow), ki= " << ki << " " << regions_[ki].get() << std::endl; +#endif + } + // for (int kh=0; kh<(int)surfaces_.size(); ++kh) + // { + // int numreg = surfaces_[kh]->numRegions(); + // for (int ka=0; ka<numreg; ++ka) + // { + // RevEngRegion *reg = surfaces_[kh]->getRegion(ka); + // size_t kr; + // for (kr=0; kr<regions_.size(); ++kr) + // if (reg == regions_[kr].get()) + // break; + // if (kr == regions_.size()) + // std::cout << "Region4, surface 1. Obsolete region pointer, ki=" << ki << ", kh=" << kh << ". Region: " << reg << ", surface: " << surfaces_[kh].get() << std::endl; + // } + // } + } + + // Update adjacency between regions + for (size_t ki=0; ki<regions_.size(); ++ki) + { + regions_[ki]->clearRegionAdjacency(); + } + for (size_t ki=0; ki<regions_.size(); ++ki) + { + regions_[ki]->setRegionAdjacency(); + } + +#ifdef DEBUG + checkConsistence("Regions11"); + + std::cout << "Finished grow with surf, regions: " << regions_.size() << ", surfaces: " << surfaces_.size() << std::endl; + if (regions_.size() > 0) + { + std::cout << "Regions11" << std::endl; + std::ofstream of("regions11.g2"); + std::ofstream ofm("mid_regions11.g2"); + std::ofstream ofs("small_regions11.g2"); + writeRegionStage(of, ofm, ofs); + std::ofstream of0("regions11_helix.g2"); + for (int ki=0; ki<(int)regions_.size(); ++ki) + { + if (regions_[ki]->getSurfaceFlag() == PROBABLE_HELIX) + { + regions_[ki]->writeRegionInfo(of0); + if (regions_[ki]->hasSurface()) + regions_[ki]->writeSurface(of0); + } + } + if (surfaces_.size() > 0) + { + std::ofstream of("regsurf11.g2"); + writeRegionWithSurf(of); + } + } + + if (edges_.size() > 0) + { + std::ofstream ofe("edges11.g2"); + writeEdgeStage(ofe); + } +#endif +} + +//=========================================================================== +void RevEng::manageBlends1() +//=========================================================================== +{ + // Update adjacency between regions + for (size_t ki=0; ki<regions_.size(); ++ki) + { + regions_[ki]->clearRegionAdjacency(); + } + for (size_t ki=0; ki<regions_.size(); ++ki) + { + regions_[ki]->setRegionAdjacency(); + } + + +#ifdef DEBUG + std::ofstream ofu1("unresolved3.g2"); + for (size_t kr=0; kr<regions_.size(); ++kr) + { + if (regions_[kr]->hasSurface()) + continue; + if (regions_[kr]->hasAssociatedBlend()) + continue; + regions_[kr]->writeRegionPoints(ofu1); + } +#endif + +#ifdef DEBUG + if (edges_.size() > 0) + { + std::ofstream ofe("edges10.g2"); + writeEdgeStage(ofe); + } +#endif + +#ifdef DEBUG + for (int ki=0; ki<(int)regions_.size(); ++ki) + { + int num = regions_[ki]->numPoints(); + for (int ka=0; ka<num; ++ka) + if (regions_[ki]->getPoint(ka)->region() != regions_[ki].get()) + std::cout << "Inconsistent region pointers, pre createBlendSurface: " << ki << " " << ka << std::endl; + } +#endif + + // Update adjacency between regions + for (size_t ki=0; ki<regions_.size(); ++ki) + { + regions_[ki]->clearRegionAdjacency(); + } + for (size_t ki=0; ki<regions_.size(); ++ki) + { + regions_[ki]->setRegionAdjacency(); + } + +#ifdef DEBUG + std::cout << "Create blends" << std::endl; +#endif + for (size_t ki=0; ki<edges_.size(); ++ki) + (void)createBlendSurface((int)ki); + + +#ifdef DEBUG + std::cout << "Finished create blends, regions: " << regions_.size() << ", surfaces: " << surfaces_.size() << std::endl; + if (regions_.size() > 0) + { + std::cout << "Regions11_2" << std::endl; + std::ofstream of("regions11_2.g2"); + std::ofstream ofm("mid_regions11_2.g2"); + std::ofstream ofs("small_regions11_2.g2"); + writeRegionStage(of, ofm, ofs); + if (surfaces_.size() > 0) + { + std::ofstream of("regsurf11_2.g2"); + writeRegionWithSurf(of); + } + } + + if (edges_.size() > 0) + { + std::ofstream ofe("edges11_2.g2"); + writeEdgeStage(ofe); + } +#endif + + // Update blend radii + equalizeBlendRadii(); + +#ifdef DEBUG + if (regions_.size() > 0) + { + std::cout << "Regions11_3_1" << std::endl; + std::ofstream of("regions11_3_1.g2"); + std::ofstream ofm("mid_regions11_3_1.g2"); + std::ofstream ofs("small_regions11_3_1.g2"); + writeRegionStage(of, ofm, ofs); + if (surfaces_.size() > 0) + { + std::ofstream of("regsurf11_4.g2"); + writeRegionWithSurf(of); + } + } +#endif + int stop_break = 1; +} + +//=========================================================================== +void RevEng::manageBlends2() +//=========================================================================== +{ +#ifdef DEBUG + std::cout << "Set blend boundaries" << std::endl; +#endif + for (size_t ki=0; ki<surfaces_.size(); ++ki) + { + int nreg = surfaces_[ki]->numRegions(); + if (nreg != 1) + continue; // Not an issue currently + RevEngRegion *reg = surfaces_[ki]->getRegion(0); + if (reg->hasBlendEdge()) + setBlendBoundaries(reg); + } + +#ifdef DEBUG + //std::cout << "Finished set blend boundaries, regions: " << regions_.size() << ", surfaces: " << surfaces_.size() << std::endl; + if (regions_.size() > 0) + { + std::cout << "Regions11_3" << std::endl; + std::ofstream of("regions11_3.g2"); + std::ofstream ofm("mid_regions11_3.g2"); + std::ofstream ofs("small_regions11_3.g2"); + writeRegionStage(of, ofm, ofs); + if (surfaces_.size() > 0) + { + std::ofstream of("regsurf11_3.g2"); + writeRegionWithSurf(of); + } + + vector<shared_ptr<ftEdge> > trim_edgs; + for (size_t kr=0; kr<regions_.size(); ++kr) + { + // if (regions_[kr]->numPoints() == 0) + // std::cout << "Finished set blend boundaries, empty region, ki=" << kr << ", region: " << regions_[kr].get() << std::endl; + int num = regions_[kr]->numTrimEdges(); + if (num > 0) + { + vector<shared_ptr<ftEdge> > curr_edgs = regions_[kr]->getTrimEdges(); + trim_edgs.insert(trim_edgs.end(), curr_edgs.begin(), curr_edgs.end()); + } + } + if (trim_edgs.size() > 0) + { + std::ofstream oft("trim_edges11_3.g2"); + for (size_t kr=0; kr<trim_edgs.size(); ++kr) + { + shared_ptr<ParamCurve> tmp = trim_edgs[kr]->geomCurve(); + shared_ptr<CurveOnSurface> tmp2 = + dynamic_pointer_cast<CurveOnSurface,ParamCurve>(tmp); +#ifdef DEBUG_BLEND + bool same_orient = tmp2->sameOrientation(); + bool same_trace = tmp2->sameTrace(approx_tol_); + bool same_cv = tmp2->sameCurve(approx_tol_); + if ((!same_orient) || (!same_trace) || (!same_cv)) + std::cout << "Surface curve mismatch " << kr << " " << same_orient << " " << same_trace << " " << same_cv << std::endl; +#endif + shared_ptr<ParamCurve> tmp3 = tmp2->spaceCurve(); + tmp3->writeStandardHeader(oft); + tmp3->write(oft); + } + } + } + + if (edges_.size() > 0) + { + std::ofstream ofe("edges11_3.g2"); + writeEdgeStage(ofe); + } +#endif + + for (int ka=0; ka<(int)regions_.size(); ++ka) + { + if (regions_[ka]->hasSurface() && regions_[ka]->hasBlendEdge()) + growBlendSurface(ka); + } + +#ifdef DEBUG + std::cout << "Finished grow blend surface, regions: " << regions_.size() << ", surfaces: " << surfaces_.size() << std::endl; + if (regions_.size() > 0) + { + std::cout << "Regions11_3_2" << std::endl; + std::ofstream of("regions11_3_2.g2"); + std::ofstream ofm("mid_regions11_3_2.g2"); + std::ofstream ofs("small_regions11_3_2.g2"); + writeRegionStage(of, ofm, ofs); + if (surfaces_.size() > 0) + { + std::ofstream of("regsurf11_3_2.g2"); + writeRegionWithSurf(of); + } + + vector<shared_ptr<ftEdge> > trim_edgs; + for (size_t kr=0; kr<regions_.size(); ++kr) + { + if (regions_[kr]->numPoints() == 0) + std::cout << "Finished grow blend surface, empty region, ki=" << kr << ", region: " << regions_[kr].get() << std::endl; + int num = regions_[kr]->numTrimEdges(); + if (num > 0) + { + vector<shared_ptr<ftEdge> > curr_edgs = regions_[kr]->getTrimEdges(); + trim_edgs.insert(trim_edgs.end(), curr_edgs.begin(), curr_edgs.end()); + } + } + if (trim_edgs.size() > 0) + { + std::ofstream oft("trim_edges11_3_2.g2"); + for (size_t kr=0; kr<trim_edgs.size(); ++kr) + { + shared_ptr<ParamCurve> tmp = trim_edgs[kr]->geomCurve(); + shared_ptr<CurveOnSurface> tmp2 = + dynamic_pointer_cast<CurveOnSurface,ParamCurve>(tmp); +#ifdef DEBUG_BLEND + bool same_orient = tmp2->sameOrientation(); + bool same_trace = tmp2->sameTrace(approx_tol_); + bool same_cv = tmp2->sameCurve(approx_tol_); + if ((!same_orient) || (!same_trace) || (!same_cv)) + std::cout << "Surface curve mismatch " << kr << " " << same_orient << " " << same_trace << " " << same_cv << std::endl; +#endif + shared_ptr<ParamCurve> tmp3 = tmp2->spaceCurve(); + tmp3->writeStandardHeader(oft); + tmp3->write(oft); + } + } + } + + if (edges_.size() > 0) + { + std::ofstream ofe("edges11_3_2.g2"); + writeEdgeStage(ofe); + } +#endif + + for (int ka=0; ka<(int)regions_.size(); ++ka) + { + if (regions_[ka]->hasSurface() && regions_[ka]->numTrimEdges() > 0 && + (!regions_[ka]->hasBlendEdge())) + { + vector<vector<RevEngPoint*> > added_groups; + vector<HedgeSurface*> dummy_surfs; + double tol = 1.5*approx_tol_; + double angtol = 5.0*anglim_; + regions_[ka]->removeLowAccuracyPoints(min_point_region_, + tol, angtol, added_groups); + if (added_groups.size() > 0) + surfaceExtractOutput(ka, added_groups, dummy_surfs); + } + } + + for (int ka=0; ka<(int)regions_.size(); ++ka) + { + if (regions_[ka]->hasSurface() && regions_[ka]->numTrimEdges() > 0) + growMasterSurface(ka); + } + +#ifdef DEBUG + std::cout << "Finished grow blend surface, regions: " << regions_.size() << ", surfaces: " << surfaces_.size() << std::endl; + if (regions_.size() > 0) + { + std::cout << "Regions11_3_3" << std::endl; + std::ofstream of("regions11_3_3.g2"); + std::ofstream ofm("mid_regions11_3_3.g2"); + std::ofstream ofs("small_regions11_3_3.g2"); + writeRegionStage(of, ofm, ofs); + if (surfaces_.size() > 0) + { + std::ofstream of("regsurf11_3_3.g2"); + writeRegionWithSurf(of); + } + + vector<shared_ptr<ftEdge> > trim_edgs; + for (size_t kr=0; kr<regions_.size(); ++kr) + { + if (regions_[kr]->numPoints() == 0) + std::cout << "Grow master surface, empty region, ki=" << kr << ", region: " << regions_[kr].get() << std::endl; + int num = regions_[kr]->numTrimEdges(); + if (num > 0) + { + vector<shared_ptr<ftEdge> > curr_edgs = regions_[kr]->getTrimEdges(); + trim_edgs.insert(trim_edgs.end(), curr_edgs.begin(), curr_edgs.end()); + } + } + if (trim_edgs.size() > 0) + { + std::ofstream oft("trim_edges11_3_3.g2"); + for (size_t kr=0; kr<trim_edgs.size(); ++kr) + { + shared_ptr<ParamCurve> tmp = trim_edgs[kr]->geomCurve(); + shared_ptr<CurveOnSurface> tmp2 = + dynamic_pointer_cast<CurveOnSurface,ParamCurve>(tmp); +#ifdef DEBUG_BLEND + bool same_orient = tmp2->sameOrientation(); + bool same_trace = tmp2->sameTrace(approx_tol_); + bool same_cv = tmp2->sameCurve(approx_tol_); + if ((!same_orient) || (!same_trace) || (!same_cv)) + std::cout << "Surface curve mismatch " << kr << " " << same_orient << " " << same_trace << " " << same_cv << std::endl; +#endif + shared_ptr<ParamCurve> tmp3 = tmp2->spaceCurve(); + tmp3->writeStandardHeader(oft); + tmp3->write(oft); + } + } + } + + if (edges_.size() > 0) + { + std::ofstream ofe("edges11_3_3.g2"); + writeEdgeStage(ofe); + } +#endif + +#ifdef DEBUG_BLEND + std::ofstream ofbb("blend_branch.g2"); + vector<RevEngPoint*> bbpts; + for (size_t kr=0; kr<regions_.size(); ++kr) + { + if (!regions_[kr]->hasBlendEdge()) + continue; + vector<RevEngPoint*> currbb = regions_[kr]->extractBranchPoints(); + if (currbb.size() > 0) + bbpts.insert(bbpts.end(), currbb.begin(), currbb.end()); + } + if (bbpts.size() > 0) + { + ofbb << "400 1 0 4 0 0 0 255" << std::endl; + ofbb << bbpts.size() << std::endl; + for (size_t kr=0; kr<bbpts.size(); ++kr) + ofbb << bbpts[kr]->getPoint() << std::endl; + } +#endif + + // TESTING. Update adjacency between regions + for (size_t ki=0; ki<regions_.size(); ++ki) + { + regions_[ki]->clearRegionAdjacency(); + } + for (size_t ki=0; ki<regions_.size(); ++ki) + { + regions_[ki]->setRegionAdjacency(); + } + +#ifdef DEBUG + std::cout << "Torus corners" << std::endl; +#endif + + for (size_t ki=0; ki<regions_.size(); ++ki) + { + if (regions_[ki]->toBeRemoved()) + continue; + + if (!regions_[ki]->hasSurface()) + continue; + + if (!regions_[ki]->hasBlendEdge()) + continue; + + bool done = defineTorusCorner(ki); +#ifdef DEBUG_BLEND + std::ofstream ofsfs("curr_sfs.g2"); + for (size_t kj=0; kj<regions_.size(); ++kj) + { + if (regions_[kj]->hasSurface()) + { + shared_ptr<ParamSurface> curr_sf = regions_[kj]->getSurface(0)->surface(); + curr_sf->writeStandardHeader(ofsfs); + curr_sf->write(ofsfs); + } + } + int stop_tor = 1; +#endif + } + vector<RevEngRegion*> removereg; + vector<HedgeSurface*> removehedge; + for (size_t ki=0; ki<regions_.size(); ++ki) + { + if (regions_[ki]->toBeRemoved()) + { + removereg.push_back(regions_[ki].get()); + int num_sfs = regions_[ki]->numSurface(); + for (int ka=0; ka<num_sfs; ++ka) + removehedge.push_back(regions_[ki]->getSurface(ka)); + } + } + if (removereg.size() > 0) + { + int dummy_ix = 0; + updateRegionsAndSurfaces(dummy_ix, removereg, removehedge); + } + +#ifdef DEBUG + std::cout << "Finished torus corners, regions: " << regions_.size() << ", surfaces: " << surfaces_.size() << std::endl; + if (regions_.size() > 0) + { + std::cout << "Regions11_4" << std::endl; + std::ofstream of("regions11_4.g2"); + std::ofstream ofm("mid_regions11_4.g2"); + std::ofstream ofs("small_regions11_4.g2"); + writeRegionStage(of, ofm, ofs); + if (surfaces_.size() > 0) + { + std::ofstream of("regsurf11_4.g2"); + writeRegionWithSurf(of); + } + + vector<shared_ptr<ftEdge> > trim_edgs; + for (size_t kr=0; kr<regions_.size(); ++kr) + { + // if (regions_[kr]->numPoints() == 0) + // std::cout << "Torus corner, ki=" << kr << ", region: " << regions_[kr].get() << std::endl; + int num = regions_[kr]->numTrimEdges(); + if (num > 0) + { + vector<shared_ptr<ftEdge> > curr_edgs = regions_[kr]->getTrimEdges(); + trim_edgs.insert(trim_edgs.end(), curr_edgs.begin(), curr_edgs.end()); + } + } + if (trim_edgs.size() > 0) + { + std::ofstream oft("trim_edges11_4.g2"); + for (size_t kr=0; kr<trim_edgs.size(); ++kr) + { + shared_ptr<ParamCurve> tmp = trim_edgs[kr]->geomCurve(); + shared_ptr<CurveOnSurface> tmp2 = + dynamic_pointer_cast<CurveOnSurface,ParamCurve>(tmp); +#ifdef DEBUG_BLEND + bool same_orient = tmp2->sameOrientation(); + bool same_trace = tmp2->sameTrace(approx_tol_); + bool same_cv = tmp2->sameCurve(approx_tol_); + if ((!same_orient) || (!same_trace) || (!same_cv)) + std::cout << "Surface curve mismatch " << kr << " " << same_orient << " " << same_trace << " " << same_cv << std::endl; +#endif + shared_ptr<ParamCurve> tmp3 = tmp2->spaceCurve(); + tmp3->writeStandardHeader(oft); + tmp3->write(oft); + } + } + } +#endif + // Update adjacency between regions + for (size_t ki=0; ki<regions_.size(); ++ki) + { + regions_[ki]->clearRegionAdjacency(); + } + for (size_t ki=0; ki<regions_.size(); ++ki) + { + regions_[ki]->setRegionAdjacency(); + } + + vector<RevEngRegion*> cand_corner_adj; + for (size_t ki=0; ki<regions_.size(); ++ki) + { + if (!regions_[ki]->hasBlendEdge()) + continue; + if (regions_[ki]->getBlendEdge()->isClosed(approx_tol_)) + continue; + int num_edg = regions_[ki]->numTrimEdges(); + if (num_edg < 4) + cand_corner_adj.push_back(regions_[ki].get()); + } + +#ifdef DEBUG_BLEND + std::ofstream ofmb0("adj_candidate_blend_corner.g2"); + for (size_t ki=0; ki<cand_corner_adj.size(); ++ki) + { + cand_corner_adj[ki]->writeRegionPoints(ofmb0); + cand_corner_adj[ki]->writeSurface(ofmb0); + } +#endif + if (cand_corner_adj.size() > 2) + defineMissingCorner(cand_corner_adj); + + removereg.clear(); + removehedge.clear(); + for (size_t ki=0; ki<regions_.size(); ++ki) + { + if (regions_[ki]->toBeRemoved()) + { + removereg.push_back(regions_[ki].get()); + int num_sfs = regions_[ki]->numSurface(); + for (int ka=0; ka<num_sfs; ++ka) + removehedge.push_back(regions_[ki]->getSurface(ka)); + } + } + if (removereg.size() > 0) + { + int dummy_ix = 0; + updateRegionsAndSurfaces(dummy_ix, removereg, removehedge); + } + +#ifdef DEBUG + std::cout << "Finished missing corners, regions: " << regions_.size() << ", surfaces: " << surfaces_.size() << std::endl; + if (regions_.size() > 0) + { + std::cout << "Regions11_5" << std::endl; + std::ofstream of("regions11_5.g2"); + std::ofstream ofm("mid_regions11_5.g2"); + std::ofstream ofs("small_regions11_5.g2"); + writeRegionStage(of, ofm, ofs); + if (surfaces_.size() > 0) + { + std::ofstream of("regsurf11_5.g2"); + writeRegionWithSurf(of); + } + + vector<shared_ptr<ftEdge> > trim_edgs; + for (size_t kr=0; kr<regions_.size(); ++kr) + { + // if (regions_[kr]->numPoints() == 0) + // std::cout << "Missing corner, ki=" << kr << ", region: " << regions_[kr].get() << std::endl; + int num = regions_[kr]->numTrimEdges(); + if (num > 0) + { + vector<shared_ptr<ftEdge> > curr_edgs = regions_[kr]->getTrimEdges(); + trim_edgs.insert(trim_edgs.end(), curr_edgs.begin(), curr_edgs.end()); + } + } + if (trim_edgs.size() > 0) + { + std::ofstream oft("trim_edges11_5.g2"); + for (size_t kr=0; kr<trim_edgs.size(); ++kr) + { + shared_ptr<ParamCurve> tmp = trim_edgs[kr]->geomCurve(); + shared_ptr<CurveOnSurface> tmp2 = + dynamic_pointer_cast<CurveOnSurface,ParamCurve>(tmp); +#ifdef DEBUG_BLEND + bool same_orient = tmp2->sameOrientation(); + bool same_trace = tmp2->sameTrace(approx_tol_); + bool same_cv = tmp2->sameCurve(approx_tol_); + if ((!same_orient) || (!same_trace) || (!same_cv)) + std::cout << "Surface curve mismatch " << kr << " " << same_orient << " " << same_trace << " " << same_cv << std::endl; +#endif + shared_ptr<ParamCurve> tmp3 = tmp2->spaceCurve(); + tmp3->writeStandardHeader(oft); + tmp3->write(oft); + } + } + } +#endif + + int stop_break_blend = 1; + +} + + +//=========================================================================== +void RevEng::equalizeBlendRadii() +//=========================================================================== +{ + // Equialize adjacent blends between the same surfaces + for (size_t ki=0; ki<regions_.size(); ++ki) + { + if (!regions_[ki]->hasSurface()) + continue; + + if (!regions_[ki]->hasBlendEdge()) + continue; + + RevEngEdge *edge1 = regions_[ki]->getBlendEdge(); + RevEngRegion* adj1[2]; + edge1->getAdjacent(adj1[0], adj1[1]); + + + for (size_t kj=ki+1; kj<regions_.size(); ++kj) + { + if (!regions_[kj]->hasSurface()) + continue; + + if (!regions_[kj]->hasBlendEdge()) + continue; + + RevEngEdge *edge2 = regions_[kj]->getBlendEdge(); + RevEngRegion* adj2[2]; + edge2->getAdjacent(adj2[0], adj2[1]); + + if ((adj1[0] == adj2[0] || adj1[0] == adj2[1]) && + (adj1[1] == adj2[0] || adj1[1] == adj2[1])) + { +#ifdef DEBUG_BLEND + std::ofstream of("adj_blend.g2"); + regions_[ki]->writeRegionPoints(of); + regions_[kj]->writeRegionPoints(of); +#endif + double par1, par2; + bool is_adjacent = edge1->isAdjacent(edge2, approx_tol_, par1, + par2); + if (is_adjacent) + equalizeAdjacent(ki, kj); + } + } + + } + + // Collect information about blend radii + vector<double> rad; + for (size_t ki=0; ki<regions_.size(); ++ki) + { + if (!regions_[ki]->hasSurface()) + continue; + + if (!regions_[ki]->hasBlendEdge()) + continue; + + shared_ptr<ParamSurface> surf = regions_[ki]->getSurface(0)->surface(); + shared_ptr<ElementarySurface> elem = + dynamic_pointer_cast<ElementarySurface, ParamSurface>(surf); + if (!elem.get()) + continue; + + double radius = elem->radius(0.0, 0.0); + double radius2 = elem->radius2(0.0, 0.0); + if (radius2 > 0) + rad.push_back(radius2); + else + rad.push_back(radius); + } + + if (rad.size() == 0) + return; + + std::sort(rad.begin(), rad.end()); + vector<size_t> ixs; + ixs.push_back(0); + double tmean = rad[0]; + size_t prev = 0; + int nn = 1; + size_t ki=1; + double fac = 0.5; + double curr_mean, range; + for (; ki<rad.size(); ++ki) + { + curr_mean = (tmean + rad[ki])/(double)(nn+1); + range = rad[ki]-rad[prev]; + if (range < fac*curr_mean) + { + tmean += rad[ki]; + ++nn; + } + else + { + ixs.push_back(ki); + prev = ki; + tmean = rad[ki]; + nn = 1; + } + int stop_break0 = 1; + } + + vector<pair<double,double> > rad_range; + for (ki=1; ki<ixs.size(); ++ki) + rad_range.push_back(std::make_pair(rad[ixs[ki-1]], rad[ixs[ki]-1])); + rad_range.push_back(std::make_pair(rad[ixs[ixs.size()-1]], rad[rad.size()-1])); + + vector<double> mean_rad(rad_range.size()); + for (ki=0; ki<rad_range.size(); ++ki) + { + mean_rad[ki] = 0.5*(rad_range[ki].first + rad_range[ki].second); + if (mean_rad[ki] <= 0.1) + { + double low = 0.01*(double)((int)(100.0*mean_rad[ki])); + double high = 0.01*(double)((int)(100.0*mean_rad[ki]+1)); + mean_rad[ki] = (mean_rad[ki]-low < high-mean_rad[ki]) ? low : high; + } + else if (mean_rad[ki] <= 1.0) + { + double low = 0.1*(double)((int)(10.0*mean_rad[ki])); + double high = 0.1*(double)((int)(10.0*mean_rad[ki]+1)); + mean_rad[ki] = (mean_rad[ki]-low < high-mean_rad[ki]) ? low : high; + } + else if (mean_rad[ki] <= 10.0) + { + double low = (double)((int)(mean_rad[ki])); + double high = (double)((int)(mean_rad[ki]+1)); + double mid = 0.5*(low+high); + mean_rad[ki] = (mean_rad[ki]-low < std::min(fabs(mean_rad[ki]-mid), high-mean_rad[ki])) ? + low : ((high-mean_rad[ki]) < fabs(mean_rad[ki]-mid) ? high : mid);; + } + else + { + double low = (double)((int)(mean_rad[ki])); + double high = (double)((int)(mean_rad[ki]+1)); + mean_rad[ki] = (mean_rad[ki]-low < high-mean_rad[ki]) ? low : high; + } + } + + for (ki=0; ki<regions_.size(); ++ki) + { + if (!regions_[ki]->hasSurface()) + continue; + + if (!regions_[ki]->hasBlendEdge()) + continue; + + shared_ptr<ParamSurface> surf = regions_[ki]->getSurface(0)->surface(); + shared_ptr<ElementarySurface> elem = + dynamic_pointer_cast<ElementarySurface, ParamSurface>(surf); + if (!elem.get()) + continue; + + double radius = elem->radius(0.0, 0.0); + double radius2 = elem->radius2(0.0, 0.0); + if (radius2 > 0.0) + radius = radius2; + + size_t kj; + for (kj=0; kj<rad_range.size(); ++kj) + if (radius >= rad_range[kj].first && radius <= rad_range[kj].second) + { + updateBlendRadius(ki, mean_rad[kj]); + break; + } + } + + int stop_break = 1; + +} + +//=========================================================================== +void RevEng::equalizeAdjacent(size_t ix1, size_t ix2) +//=========================================================================== +{ + shared_ptr<ParamSurface> surf1 = regions_[ix1]->getSurface(0)->surface(); + shared_ptr<ParamSurface> surf2 = regions_[ix2]->getSurface(0)->surface(); + if ((!surf1) || (!surf2)) + return; + + if (surf1->instanceType() != surf2->instanceType()) + return; + + double angtol = 5.0*anglim_; + shared_ptr<ElementarySurface> elem1 = + dynamic_pointer_cast<ElementarySurface,ParamSurface>(surf1); + shared_ptr<ElementarySurface> elem2 = + dynamic_pointer_cast<ElementarySurface,ParamSurface>(surf2); + Point axis1 = elem1->direction(); + Point axis2 = elem1->direction(); + double ang = axis1.angle(axis2); + ang = std::min(ang, M_PI-ang); + if (ang > angtol) + return; + Point pos1 = elem1->location(); + Point pos2 = elem2->location(); + double rad1 = elem1->radius(0.0, 0.0); + double rad2 = elem2->radius(0.0, 0.0); + double fac = 0.1; + double fac2 = 0.25; + if (fabs(rad1-rad2) > fac*std::max(rad1, rad2)) + return; // Too large difference + double rad = 0.5*(rad1 + rad2); + + if (axis1*axis2 < 0.0) + axis2 *= -1; + Point axis = 0.5*(axis1 + axis2); + axis.normalize(); + + Point Cx; + Point Cx1 = elem1->direction2(); + Point Cx2 = elem2->direction2(); + double ang2 = Cx1.angle(Cx2); + if (ang2 <= angtol || M_PI-ang2 <= angtol) + { + if (Cx1*Cx2 < 0.0) + Cx2 *= -1; + Cx = 0.5*(Cx1 + Cx2); + Point Cy = axis.cross(Cx); + Cx = Cy.cross(axis); + Cx.normalize(); + } + else + { + int ka = -1; + double minang = std::numeric_limits<double>::max(); + for (int kb=0; kb<3; ++kb) + { + double ang3 = mainaxis_[kb].angle(axis); + ang3 = std::min(ang3, M_PI-ang3); + if (ang3 < minang) + { + minang = ang3; + ka = kb; + } + } + if (ka < 0) + return; + int kb = (ka > 0) ? ka - 1 : 2; + Cx = mainaxis_[kb].cross(axis); + } + + RectDomain dom1 = elem1->getParameterBounds(); + RectDomain dom2 = elem2->getParameterBounds(); + shared_ptr<ElementarySurface> upd1, upd2; + bool cyllike = true; + if (surf1->instanceType() == Class_Cylinder) + { + Point pos2_2 = pos1 + ((pos2 - pos1)*axis)*axis; + if (pos2.dist(pos2_2) > approx_tol_) + return; + + Point pos1_2 = pos2 + ((pos1 - pos2)*axis)*axis; + if (pos1.dist(pos1_2) > approx_tol_) + return; + + Point pos3 = 0.5*(pos1_2 + pos2_2); // Point on updated axis + Point pos3_1 = pos3 + ((pos1 - pos3)*axis)*axis; + Point pos3_2 = pos3 + ((pos2 - pos3)*axis)*axis; + + double rad = 0.5*(rad1 + rad2); + upd1 = shared_ptr<Cylinder>(new Cylinder(rad, pos3_1, axis, Cx)); + upd2 = shared_ptr<Cylinder>(new Cylinder(rad, pos3_2, axis, Cx)); + + double upar1 = 0.5*(dom1.umin() + dom2.umin()); // Could be a problem if + // the direction of Cx is changed significantly + double upar2 = 0.5*(dom1.umax() + dom2.umax()); + upd1->setParameterBounds(upar1, dom1.vmin(), upar2, dom1.vmax()); + upd2->setParameterBounds(upar1, dom2.vmin(), upar2, dom2.vmax()); + cyllike = true; + } + else if (surf1->instanceType() == Class_Torus) + { + Point pos2_2 = pos1 + ((pos2 - pos1)*axis)*axis; + if (pos2_2.dist(pos2) > approx_tol_) + return; + + double minrad1 = elem1->radius2(0.0, 0.0); + double minrad2 = elem2->radius2(0.0, 0.0); + if (fabs(minrad1-minrad2) > fac2*std::max(minrad1, minrad2)) + return; + + Point centre = 0.5*(pos1 + pos2); + double minrad = 0.5*(minrad1 + minrad2); + upd1 = shared_ptr<Torus>(new Torus(rad, minrad, centre, axis, Cx)); + upd2 = shared_ptr<Torus>(new Torus(rad, minrad, centre, axis, Cx)); + double vpar1 = 0.5*(dom1.vmin() + dom2.vmin()); + double vpar2 = 0.5*(dom1.vmax() + dom2.vmax()); + upd1->setParameterBounds(dom1.umin(), vpar1, dom1.umax(), vpar2); + upd2->setParameterBounds(dom2.umin(), vpar1, dom2.umax(), vpar2); + cyllike = false; + } + else + return; // Not supported +#ifdef DEBUG_BLEND + std::ofstream of("updated_adjacent.g2"); + upd1->writeStandardHeader(of); + upd1->write(of); + upd2->writeStandardHeader(of); + upd2->write(of); +#endif + + // Parameterize points + double maxd1, avd1; + int nmb_in1, nmb2_in1; + vector<RevEngPoint*> in1, out1; + vector<pair<double,double> > dist_ang1; + vector<double> parvals1; + RevEngUtils::distToSurf(regions_[ix1]->pointsBegin(), regions_[ix1]->pointsEnd(), + upd1, approx_tol_, maxd1, avd1, nmb_in1, nmb2_in1, in1, out1, + parvals1, dist_ang1, angtol); + int sf_flag1 = regions_[ix1]->defineSfFlag(0, approx_tol_, nmb_in1, nmb2_in1, avd1, + cyllike); + int num_pts1 = regions_[ix1]->numPoints(); + for (int ka=0; ka<num_pts1; ++ka) + { + RevEngPoint *curr = regions_[ix1]->getPoint(ka); + curr->setPar(Vector2D(parvals1[2*ka],parvals1[2*ka+1])); + curr->setSurfaceDist(dist_ang1[ka].first, dist_ang1[ka].second); + } + regions_[ix1]->updateInfo(approx_tol_, angtol); + regions_[ix1]->setSurfaceFlag(sf_flag1); + + // Replace Surface + regions_[ix1]->getSurface(0)->replaceSurf(upd1); + + double maxd2, avd2; + int nmb_in2, nmb2_in2; + vector<RevEngPoint*> in2, out2; + vector<pair<double,double> > dist_ang2; + vector<double> parvals2; + RevEngUtils::distToSurf(regions_[ix2]->pointsBegin(), regions_[ix2]->pointsEnd(), + upd1, approx_tol_, maxd2, avd2, nmb_in2, nmb2_in2, in2, out2, + parvals2, dist_ang2, angtol); + int sf_flag2 = regions_[ix2]->defineSfFlag(0, approx_tol_, nmb_in2, nmb2_in2, avd2, + cyllike); + int num_pts2 = regions_[ix2]->numPoints(); + for (int ka=0; ka<num_pts2; ++ka) + { + RevEngPoint *curr = regions_[ix2]->getPoint(ka); + curr->setPar(Vector2D(parvals2[2*ka],parvals2[2*ka+1])); + curr->setSurfaceDist(dist_ang2[ka].first, dist_ang2[ka].second); + } + regions_[ix2]->updateInfo(approx_tol_, angtol); + regions_[ix2]->setSurfaceFlag(sf_flag2); + + // Replace Surface + regions_[ix2]->getSurface(0)->replaceSurf(upd2); + +} + +//=========================================================================== +void RevEng::updateBlendRadius(size_t ix, double radius) +//=========================================================================== +{ + double angtol = 5.0*anglim_; + double eps = 1.0e-6; + RevEngEdge *edge = regions_[ix]->getBlendEdge(); + RevEngRegion* adj[2]; + edge->getAdjacent(adj[0], adj[1]); + + if ((!adj[0]->hasSurface()) || (!adj[1]->hasSurface())) + return; // Something wrong + + bool out1 = false, out2 = false; + edge->getOuterInfo(out1, out2); + + // Intersection curve + vector<shared_ptr<CurveOnSurface> > cvs; + edge->getCurve(cvs); + vector<Point> der(2); + cvs[0]->point(der, 0.5*(cvs[0]->startparam()+cvs[0]->endparam()), 1); + + shared_ptr<ParamSurface> surf = regions_[ix]->getSurface(0)->surface(); + shared_ptr<Cylinder> init_cyl = + dynamic_pointer_cast<Cylinder, ParamSurface>(surf); + shared_ptr<Torus> init_tor = + dynamic_pointer_cast<Torus, ParamSurface>(surf); + if ((!init_cyl.get()) && (!init_tor.get())) + return; + shared_ptr<ParamSurface> surf1 = adj[0]->getSurface(0)->surface(); + shared_ptr<ParamSurface> surf2 = adj[1]->getSurface(0)->surface(); + shared_ptr<ElementarySurface> elem1 = + dynamic_pointer_cast<ElementarySurface,ParamSurface>(surf1); + shared_ptr<ElementarySurface> elem2 = + dynamic_pointer_cast<ElementarySurface,ParamSurface>(surf2); + shared_ptr<ElementarySurface> upd_blend; + double ylen; + double init_rad; + Point dir1 = elem1->direction(); + Point norm1 = adj[0]->getMeanNormalTriang(); + if (elem1->instanceType() == Class_Plane && dir1*norm1 < 0.0) + dir1 *= -1; + Point dir2 = elem2->direction(); + Point norm2 = adj[1]->getMeanNormalTriang(); + if (elem2->instanceType() == Class_Plane && dir2*norm2 < 0.0) + dir2 *= -1; + if (init_cyl.get()) + { + if (elem1->instanceType() != Class_Plane || elem2->instanceType() != Class_Plane) + return; + + Point lin1, lin2; + Point dir1_2 = dir1, dir2_2 = dir2; + if (elem1->instanceType() == Class_Plane) + lin1 = der[1].cross(dir1); + else + { + double clo_u, clo_v, clo_dist; + Point clo; + surf1->closestPoint(der[0], clo_u, clo_v, clo, clo_dist, eps); + surf1->normal(dir1_2, clo_u, clo_v); + lin1 = der[1].cross(dir1_2); + } + + if (elem2->instanceType() == Class_Plane) + lin2 = der[1].cross(dir2); + else + { + double clo_u, clo_v, clo_dist; + Point clo; + surf2->closestPoint(der[0], clo_u, clo_v, clo, clo_dist, eps); + surf2->normal(dir2_2, clo_u, clo_v); + lin2 = der[1].cross(dir2_2); + } + + // Create new cylinder + Point axis = init_cyl->direction(); + Point Cx = init_cyl->direction2(); + init_rad = init_cyl->getRadius(); + lin1.normalize(); + if (lin1*dir2_2 < 0.0) + lin1 *= -1; + lin2.normalize(); + if (lin2*dir1_2 < 0.0) + lin2 *= -1; + + Point vec = lin1 + lin2; + vec.normalize(); + double alpha = lin1.angle(lin2); + double fac = 1.0/sin(0.5*alpha); + int sgn = (out1 && out2) ? 1 : -1; + Point loc = der[0] + sgn*fac*radius*vec; + double xlen = der[0].dist(loc); + ylen = sqrt(xlen*xlen - radius*radius); + + upd_blend = shared_ptr<Cylinder>(new Cylinder(radius, loc, axis, Cx)); + } + else if (init_tor.get()) + { + // int plane_ix = 0; + // if (elem2->instanceType() == Class_Plane) + // { + // std::swap(elem1, elem2); + // plane_ix = 1; + // } + // if (elem1->instanceType() != Class_Plane) + // return; + // if (elem2->instanceType() != Class_Cylinder && + // elem2->instanceType() != Class_Cone) + // return; + + // init_rad = init_tor->radius2(0.0, 0.0); + + // bool rot_out = (plane_ix == 0) ? out2 : out1; + // bool plane_out = (plane_ix == 0) ? out1 : out2; + // int sgn1 = plane_out ? -1 : 1; + // int sgn2 = rot_out ? -1 : 1; + // Point normal0 = elem1->direction(); + // Point norm1 = adj[plane_ix]->getMeanNormalTriang(); + // if (normal0*norm1 < 0.0) + // sgn1 *= -1; + + bool plane1 = (elem1->instanceType() == Class_Plane); + bool plane2 = (elem2->instanceType() == Class_Plane); + shared_ptr<Cone> cone1 = dynamic_pointer_cast<Cone,ElementarySurface>(elem1); + shared_ptr<Cone> cone2 = dynamic_pointer_cast<Cone,ElementarySurface>(elem2); + shared_ptr<ElementarySurface> rotational; + if (plane1) + rotational = elem2; + else if (plane2) + rotational = elem1; + else if (cone1.get()) + rotational = elem2; // elem2 is expected to be a cylinder + else if (cone2.get()) + rotational = elem1; + double alpha1 = 0.0, alpha2 = 0.0; + if (cone1.get()) + alpha1 = cone1->getConeAngle(); + if (cone2.get()) + alpha2 = cone2->getConeAngle(); + double alpha = fabs(alpha1) + fabs(alpha2); + double beta = (plane1 || plane2) ? 0.5*M_PI + alpha : M_PI-fabs(alpha); + double phi2 = 0.5*(M_PI - beta); + Point axis = rotational->direction(); + Point loc = rotational->location(); + double rd = (der[0]-loc)*axis; + Point centr = loc + rd*axis; + double hh = init_tor->location().dist(centr); + init_rad = init_tor->radius2(0.0, 0.0); + double d2 = hh/sin(phi2) - init_rad; + int sgn = 1; + if ((elem1->instanceType() == Class_Plane && elem1->direction()*dir1 < 0.0) || + (elem2->instanceType() == Class_Plane && elem2->direction()*dir2 < 0.0)) + sgn = -1; + double Rrad; + Point centre, normal, Cx; + bool OK = getTorusParameters(elem1, elem2, der[0], radius, d2, out1, out2, + sgn, Rrad, centre, normal, Cx); + if (!OK) + return; // Don't change + + upd_blend = shared_ptr<Torus>(new Torus(Rrad, radius, centre, normal, Cx)); + + // bool setbounds = false; + // if ((plane1 && out2) || (plane2 && out1) || + // (plane1 && false && plane2 == false && + // ((cone1.get() && out1 == false) || (cone2.get() && out2 == false)))) + // setbounds = true; + + // if (setbounds) + // { + RectDomain dom = init_tor->getParameterBounds(); + upd_blend->setParameterBounds(dom.umin(), dom.vmin()-M_PI, + dom.umax(), dom.vmax()-M_PI); + // } + double xlen = der[0].dist(centre); + ylen = fabs(xlen - Rrad); + } + + // RectDomain dom = init_cyl->getParameterBounds(); + // cyl->setParameterBounds(dom.umin(), dom.vmin(), dom.umax(), dom.vmax()); +#ifdef DEBUG_BLEND + std::ofstream of("blend2.g2"); + regions_[ix]->writeRegionPoints(of); + surf->writeStandardHeader(of); + surf->write(of); + + adj[0]->writeRegionPoints(of); + adj[1]->writeRegionPoints(of); + upd_blend->writeStandardHeader(of); + upd_blend->write(of); + RectDomain dom2 = upd_blend->getParameterBounds(); + vector<shared_ptr<ParamCurve> > tmp_cvs = upd_blend->constParamCurves(dom2.vmin(), true); + tmp_cvs[0]->writeStandardHeader(of); + tmp_cvs[0]->write(of); +#endif + + if (radius < init_rad) + { + // Move outside points from the blend surface to the adjacent + // surfaces. If the new radius is larger than the initial one, + // moving of points will be performed by the next function + vector<RevEngPoint*> points(regions_[ix]->pointsBegin(), regions_[ix]->pointsEnd()); + vector<vector<RevEngPoint*> > out_pts(2); + adj[0]->sortBlendPoints(points, cvs, ylen, adj[1], out_pts[0], out_pts[1]); + vector<RevEngPoint*> all_out; + if (out_pts[0].size() > 0) + all_out.insert(all_out.end(), out_pts[0].begin(), out_pts[0].end()); + if (out_pts[1].size() > 0) + all_out.insert(all_out.end(), out_pts[1].begin(), out_pts[1].end()); + if (all_out.size() > 0) + regions_[ix]->removePoints(all_out); + + for (int ka=0; ka<2; ++ka) + { + vector<RevEngPoint*> to_blend; // Not here + adj[ka]->updateWithPointsInOut(to_blend, out_pts[ka], approx_tol_, angtol); + } + } + + // Parameterize remaining points + double maxd, avd; + int nmb_in, nmb2_in; + vector<RevEngPoint*> in, out; + vector<pair<double,double> > dist_ang; + vector<double> parvals; + RevEngUtils::distToSurf(regions_[ix]->pointsBegin(), regions_[ix]->pointsEnd(), + upd_blend, approx_tol_, maxd, avd, nmb_in, nmb2_in, in, out, + parvals, dist_ang, angtol); + int sf_flag = regions_[ix]->defineSfFlag(0, approx_tol_, nmb_in, nmb2_in, avd, true); + int num_pts = regions_[ix]->numPoints(); + for (int ka=0; ka<num_pts; ++ka) + { + RevEngPoint *curr = regions_[ix]->getPoint(ka); + curr->setPar(Vector2D(parvals[2*ka],parvals[2*ka+1])); + curr->setSurfaceDist(dist_ang[ka].first, dist_ang[ka].second); + } + regions_[ix]->setSurfaceFlag(sf_flag); + + // Replace Surface + regions_[ix]->getSurface(0)->replaceSurf(upd_blend); +} + + +//=========================================================================== +bool RevEng::defineTorusCorner(size_t ix) +//=========================================================================== +{ + double pihalf = 0.5*M_PI; + double angtol = 5.0*anglim_; + double blendfac = 2.0; + + shared_ptr<ParamSurface> surf1 = regions_[ix]->getSurface(0)->surface(); + if (surf1->instanceType() != Class_Cylinder) + return false; + + if (!regions_[ix]->hasBlendEdge()) + return false; + + // Bound cylinder in the length direction + double diag = bbox_.low().dist(bbox_.high()); + if (!surf1->isBounded()) + { + shared_ptr<Cylinder> cyl = dynamic_pointer_cast<Cylinder,ParamSurface>(surf1); + cyl->setParamBoundsV(-0.5*diag, 0.5*diag); + } + + RevEngEdge* blend_edge = regions_[ix]->getBlendEdge(); + RevEngRegion *adj1=0, *adj2=0; + blend_edge->getAdjacent(adj1, adj2); + + vector<RevEngEdge*> revedg1 = regions_[ix]->getAllRevEdges(); + shared_ptr<ElementarySurface> elem1 = + dynamic_pointer_cast<ElementarySurface,ParamSurface>(surf1); + Point dir1 = elem1->direction(); + +#ifdef DEBUG_BLEND + std::ofstream of0("pot_tor_adj.g2"); + surf1->writeStandardHeader(of0); + surf1->write(of0); +#endif + // Looking for a plane + bool found_torus = false; + for (size_t kj=0; kj<regions_.size(); ++kj) + { + if (kj == ix) + continue; + if (regions_[kj]->toBeRemoved()) + continue; + if (!regions_[kj]->hasSurface()) + continue; + if (regions_[kj].get() == adj1 || regions_[kj].get() == adj2) + continue; + + shared_ptr<ParamSurface> surf2 = regions_[kj]->getSurface(0)->surface(); + if (surf2->instanceType() != Class_Plane) + continue; + + if (!(regions_[ix]->isAdjacent(regions_[kj].get()) + || regions_[ix]->isNextToAdjacent(regions_[kj].get()))) + continue; + + // Check if the plane and the cylinder already has a common RevEngEdge + vector<RevEngEdge*> revedg2 = regions_[kj]->getAllRevEdges(); + size_t kr, kh; + for (kr=0; kr<revedg1.size(); ++kr) + { + for (kh=0; kh<revedg2.size(); ++kh) + if (revedg1[kr] == revedg2[kh]) + break; + if (kh < revedg2.size()) + break; + } + if (kr < revedg1.size()) + continue; + +#ifdef DEBUG_BLEND + std::ofstream of1("torus_blend1.g2"); + regions_[ix]->writeRegionPoints(of1); + regions_[ix]->writeSurface(of1); + regions_[kj]->writeRegionPoints(of1); + regions_[kj]->writeSurface(of1); +#endif + + shared_ptr<ElementarySurface> elem2 = + dynamic_pointer_cast<ElementarySurface,ParamSurface>(surf2); + if (!elem2->isBounded()) + elem2->setParameterBounds(-0.5*diag, -0.5*diag, 0.5*diag, 0.5*diag); + Point dir2 = elem2->direction(); + double ang = dir1.angle(dir2); + ang = fabs(pihalf - ang); + if (ang > blendfac*angtol) + { + double usz, vsz; + elem1->estimateSfSize(usz, vsz); + double lenlim = 0.9*usz; + + vector<shared_ptr<RevEngEdge> > edges = + defineEdgesBetween(ix, elem1, dir1, kj, elem2, dir2, false, + lenlim, false); + if (edges.size() > 0) + { + size_t ix2 = edges_.size(); + edges_.insert(edges_.end(), edges.begin(), edges.end()); + bool found = createTorusBlend(ix2); + // if (!found) + // found = createBlendSurface((int)ix2); + if (found) + found_torus = true; + else + edges_.erase(edges_.begin()+ix2, edges_.end()); + } + } + } + + return found_torus; +} + +//=========================================================================== +void RevEng::defineMissingCorner(vector<RevEngRegion*>& cand_adj) +//=========================================================================== +{ + double pihalf = 0.5*M_PI; + double angtol = 5.0*anglim_; + double diag = bbox_.low().dist(bbox_.high()); + + // Get candidate opposite regions + vector<RevEngRegion*> opposite_reg; + for (size_t ki=0; ki<cand_adj.size(); ++ki) + { + RevEngEdge* edg1 = cand_adj[ki]->getBlendEdge(); + if (!edg1) + continue; + RevEngRegion *adj1, *adj2; + edg1->getAdjacent(adj1, adj2); + if ((!adj1) || (!adj2)) + continue; + for (size_t kj=ki+1; kj<cand_adj.size(); ++kj) + { + RevEngEdge* edg2 = cand_adj[kj]->getBlendEdge(); + if (!edg2) + continue; + RevEngRegion *adj3, *adj4; + edg2->getAdjacent(adj3, adj4); + if ((!adj3) || (!adj4)) + continue; + if (adj1 == adj3 || adj1 == adj4) + opposite_reg.push_back(adj1); + if (adj2 == adj3 || adj2 == adj4) + opposite_reg.push_back(adj2); + } + } +#ifdef DEBUG_BLEND + if (opposite_reg.size() > 0) + { + std::ofstream of1("opposite_reg.g2"); + for (size_t ki=0; ki<opposite_reg.size(); ++ki) + opposite_reg[ki]->writeRegionPoints(of1); + } +#endif + + double blendfac = 2.0; + for (size_t ki=0; ki<cand_adj.size(); ++ki) + { + RevEngEdge* edg1 = cand_adj[ki]->getBlendEdge(); + RevEngRegion *adj1, *adj2; + edg1->getAdjacent(adj1, adj2); + if ((!adj1) || (!adj2)) + continue; + shared_ptr<ParamSurface> surf1 = cand_adj[ki]->getSurface(0)->surface(); + if (surf1->instanceType() != Class_Cylinder) + continue; + if (!surf1->isBounded()) + { + shared_ptr<Cylinder> cyl = + dynamic_pointer_cast<Cylinder,ParamSurface>(surf1); + cyl->setParamBoundsV(-0.5*diag, 0.5*diag); + } + shared_ptr<ElementarySurface> elem1 = + dynamic_pointer_cast<ElementarySurface,ParamSurface>(surf1); + Point dir1 = elem1->direction(); + + for (size_t kj=0; kj<opposite_reg.size(); ++kj) + { + if (!opposite_reg[kj]->hasSurface()) + continue; + if (opposite_reg[kj] == adj1 || opposite_reg[kj] == adj2) + continue; + shared_ptr<ParamSurface> surf2 = + opposite_reg[kj]->getSurface(0)->surface(); + if (surf2->instanceType() != Class_Plane) + continue; + shared_ptr<ElementarySurface> elem2 = + dynamic_pointer_cast<ElementarySurface,ParamSurface>(surf2); + if (!elem2->isBounded()) + elem2->setParameterBounds(-0.5*diag, -0.5*diag, 0.5*diag, 0.5*diag); + Point dir2 = elem2->direction(); + double ang = dir1.angle(dir2); + ang = fabs(pihalf - ang); + if (ang > blendfac*angtol) + { + double usz, vsz; + elem1->estimateSfSize(usz, vsz); + double lenlim = 0.9*usz; + + size_t kr, kh; + for (kr=0; kr<regions_.size(); ++kr) + if (regions_[kr].get() == cand_adj[ki]) + break; + if (kr == regions_.size()) + continue; + for (kh=0; kh<regions_.size(); ++kh) + if (regions_[kh].get() == opposite_reg[kj]) + break; + if (kh == regions_.size()) + continue; +#ifdef DEBUG_BLEND + std::ofstream of2("corner_adj.g2"); + regions_[kr]->writeRegionPoints(of2); + regions_[kr]->writeSurface(of2); + regions_[kh]->writeRegionPoints(of2); + regions_[kh]->writeSurface(of2); +#endif + vector<shared_ptr<RevEngEdge> > edges = + defineEdgesBetween(kr, elem1, dir1, kh, elem2, dir2, false, + lenlim, false); + if (edges.size() > 0) + { + size_t ix2 = edges_.size(); + edges_.insert(edges_.end(), edges.begin(), edges.end()); + bool found = createTorusBlend(ix2); + if (!found) + edges_.erase(edges_.begin()+ix2, edges_.end()); + } + } + + } + } + int stop_break = 1; +} + + +//=========================================================================== +bool getAdjacentToTorus(RevEngEdge* edge, vector<RevEngEdge*>& rev_edgs, + double tol, RevEngEdge*& adj_edg1, + RevEngEdge*& adj_edg2, double& rad1, double& rad2) +//=========================================================================== +{ + adj_edg1 = adj_edg2 = 0; + rad1 = rad2 = -1.0; + + Point pos1, pos2; + edge->getCrvEndPoints(pos1, pos2); + + double mindist1 = std::numeric_limits<double>::max(); + double mindist2 = std::numeric_limits<double>::max(); + int min_ix1 = -1, min_ix2 = -1; + for (size_t ki=0; ki<rev_edgs.size(); ++ki) + { + RevEngRegion *reg = rev_edgs[ki]->getBlendRegSurf(); + if (!reg) + continue; + + double tpar1, tpar2, dist1, dist2; + Point close1, close2; + rev_edgs[ki]->closestPoint(pos1, tpar1, close1, dist1); + rev_edgs[ki]->closestPoint(pos2, tpar2, close2, dist2); + if (dist1 < mindist1) + { + mindist1 = dist1; + min_ix1 = (int)ki; + } + if (dist2 < mindist2) + { + mindist2 = dist2; + min_ix2 = (int)ki; + } + int stop_break = 1; + } + if (min_ix1 < 0 && min_ix2 < 0) + return false; + if (mindist1 > tol && mindist2 > tol) + return false; // Might need to tune tolerance + + if (min_ix1 >= 0 && mindist1 <= tol) + { + adj_edg1 = rev_edgs[min_ix1]; + RevEngRegion *reg = adj_edg1->getBlendRegSurf(); + if (reg->hasSurface()) + { + shared_ptr<ParamSurface> bsurf = reg->getSurface(0)->surface(); + shared_ptr<ElementarySurface> belem = + dynamic_pointer_cast<ElementarySurface,ParamSurface>(bsurf); + if (bsurf->instanceType() == Class_Cylinder /*|| + bsurf->instanceType() == Class_Cone*/) + rad1 = belem->radius(0.0, 0.0); + else if (bsurf->instanceType() == Class_Torus) + rad1 = belem->radius2(0.0, 0.0); + } + } + if (min_ix2 >= 0 && mindist2 <= tol) + { + adj_edg2 = rev_edgs[min_ix2]; + RevEngRegion *reg = adj_edg2->getBlendRegSurf(); + if (reg->hasSurface()) + { + shared_ptr<ParamSurface> bsurf = reg->getSurface(0)->surface(); + shared_ptr<ElementarySurface> belem = + dynamic_pointer_cast<ElementarySurface,ParamSurface>(bsurf); + if (bsurf->instanceType() == Class_Cylinder /*|| + bsurf->instanceType() == Class_Cone*/) + rad2 = belem->radius(0.0, 0.0); + else if (bsurf->instanceType() == Class_Torus) + rad2 = belem->radius2(0.0, 0.0); + } + } + + if (rad1 < 0 && rad2 < 0) + return false; + + return true; +} + +//=========================================================================== +bool RevEng::createTorusBlend(size_t ix) +//=========================================================================== +{ + double eps = 1.0e-6; + double angtol = 5.0*anglim_; + double pihalf = 0.5*M_PI; + double tol2 = 2*approx_tol_; // Due to possible inaccuracies + double tol5 = 5*approx_tol_; // Due to possible inaccuracies + + // Adjacent regions + RevEngRegion* adj[2]; + edges_[ix]->getAdjacent(adj[0], adj[1]); + + if ((!adj[0]->hasSurface()) || (!adj[1]->hasSurface())) + return false; // Something wrong + + vector<shared_ptr<CurveOnSurface> > intcv1, intcv2; + edges_[ix]->getCurve(intcv1, true); + edges_[ix]->getCurve(intcv2, false); + + bool out1 = false, out2 = false; + edges_[ix]->getOuterInfo(out1, out2); + + shared_ptr<ParamSurface> surf[2]; + surf[0] = adj[0]->getSurface(0)->surface(); + surf[1] = adj[1]->getSurface(0)->surface(); + ClassType type[2]; + type[0] = surf[0]->instanceType(); + type[1] = surf[1]->instanceType(); + int jx1 = (type[0] == Class_Plane) ? 0 : + ((type[1] == Class_Plane) ? 1 : -1); + if (jx1 == -1) + return false; + int jx2 = 1 - jx1; + if (type[jx2] != Class_Cylinder) + return false; + bool outp = (jx1 == 0) ? out1 : out2; + bool outr = (jx1 == 0) ? out2 : out1; + shared_ptr<Cylinder> cyl = dynamic_pointer_cast<Cylinder,ParamSurface>(surf[jx2]); + if (!cyl.get()) + return false; // Should not happen + double radius1 = cyl->getRadius(); + + // Get adjacent blend edges and corresponding radii + vector<RevEngEdge*> rev_edgs = adj[jx1]->getAllRevEdges(); + if (rev_edgs.size() == 0) + return false; + + double rad1 = -1.0, rad2 = -1.0; + RevEngEdge *revedg1, *revedg2; + bool OK = getAdjacentToTorus(edges_[ix].get(), rev_edgs, tol5, + revedg1, revedg2, rad1, rad2); +// #ifdef DEBUG_BLEND +// if (!OK) +// std::cout << "getAdjacentToTorus not OK" << std::endl; +// if (!revedg1) +// std::cout << "getAdjacentToTorus, revedg1 missing" << std::endl; +// if (!revedg2) +// std::cout << "getAdjacentToTorus, revedg2 missing" << std::endl; +// #endif + if (!OK) + return false; + if ((!revedg1) || (!revedg2)) + return false; + bool possible_suitcase = + (fabs(rad1-rad2) > std::min(fabs(radius1-rad1), fabs(radius1-rad2))); + + double radius2 = (rad1 > 0.0 && rad2 > 0.0) ? 0.5*(rad1 + rad2) : + ((rad1 > 0.0) ? rad1 : rad2); // Should do extra checking if rad1 very + // different from rad2 and both are larger than zero + + Point loc1 = cyl->getLocation(); + Point axis1 = cyl->getAxis(); + Point Cx = cyl->direction2(); + + // The torus location coincides with the intersection point between the + // cylinder axis and the plane + shared_ptr<Plane> plane = dynamic_pointer_cast<Plane,ParamSurface>(surf[jx1]); + Point dirp = plane->direction(); + Point avnorm = adj[jx1]->getMeanNormal(); + if (dirp*avnorm < 0.0) + dirp *= -1; + if (axis1*dirp < 0.0) + axis1 *= -1; + double alpha = axis1.angle(dirp); + Point locp = plane->location(); + Point loct0 = loc1 + ((locp - loc1)*axis1)*axis1; + double d2 = locp.dist(loct0); + double xlen = d2*atan(alpha); + int sgn1 = ((locp - loct0)*dirp < 0.0) ? -1 : 1; + loct0 += sgn1*xlen*dirp; + int sgn2 = outp ? 1 : -1; + Point loct = loct0 + sgn2*radius2*dirp; + int sgn3 = outr ? -1 : 1; + double radiust = radius1 + sgn3*radius2; + if (radius2 >= radiust) + return false; // Not expecting degenerate torus + + shared_ptr<Torus> torus(new Torus(radiust, radius2, loct, dirp, Cx)); + + // Regions in blend area + vector<RevEngRegion*> blend_regs; + edges_[ix]->getAllBlendRegs(blend_regs); +#ifdef DEBUG_BLEND + std::ofstream of("torus_blend2.g2"); + for (size_t ki=0; ki<blend_regs.size(); ++ki) + blend_regs[ki]->writeRegionPoints(of); +#endif + + // Parameterize on torus + vector<RevEngPoint*> blend_pts; + for (size_t ki=0; ki<blend_regs.size(); ++ki) + blend_pts.insert(blend_pts.end(), blend_regs[ki]->pointsBegin(), + blend_regs[ki]->pointsEnd()); + double maxd, avd; + int num_in, num2_in; + vector<double> parvals; + vector<pair<double,double> > dist_ang; + vector<RevEngPoint*> inpt, outpt; + RevEngUtils::distToSurf(blend_pts.begin(), blend_pts.end(), torus, + approx_tol_, maxd, avd, num_in, num2_in, inpt, outpt, + parvals, dist_ang, angtol); + + RectDomain dom = cyl->getParameterBounds(); + if (sgn3 < 0) + torus->setParameterBounds(dom.umin(), 0.0, dom.umax(), pihalf); + else + torus->setParameterBounds(dom.umin(), M_PI, dom.umax(), 1.5*M_PI); + // What if the cylinder and the plane are not perpendicular? It is not a + // torus, but it is anyway not handled + +#ifdef DEBUG_BLEND + torus->writeStandardHeader(of); + torus->write(of); + vector<shared_ptr<ParamCurve> > c_cvs = torus->constParamCurves(0.0, true); + c_cvs[0]->writeStandardHeader(of); + c_cvs[0]->write(of); +#endif + + // Define longitudinal boundary edges of torus + RectDomain tordom = torus->getParameterBounds(); + double torlim[4]; + torlim[0] = tordom.umin(); + torlim[1] = tordom.umax(); + torlim[2] = tordom.vmin(); + torlim[3] = tordom.vmax(); + vector<shared_ptr<CurveOnSurface> > torbound(4); + for (int ka=0; ka<2; ++ka) + { + shared_ptr<Circle> circle = torus->getMajorCircle(torlim[2+ka]); + Point mid(torlim[0], torlim[2+ka]); + Point vec = Point(torlim[1],torlim[2+ka]) - Point(torlim[0],torlim[2+ka]); + vec.normalize(); + shared_ptr<Line> line(new Line(mid, vec)); + line->setParamBounds(0.0, torlim[1]-torlim[0]); + torbound[2+ka] = + shared_ptr<CurveOnSurface>(new CurveOnSurface(torus, line, circle, false, + 3, 2, torlim[2+ka], 2+ka, true)); + } + + // Restrict adjacent cylinders + // The cylinder and the edges does not necessarily have the same + // parameterization + Point pt1, pt2; + double midpar = 0.5*(tordom.vmin() + tordom.vmax()); + torus->point(pt1, tordom.umin(), midpar); + torus->point(pt2, tordom.umax(), midpar); + vector<RevEngRegion*> adj_reg(2, 0); + bool upper2[2]; + double lim[2]; + vector<shared_ptr<ElementarySurface> > adj_surf(2); + vector<double> parbound(8); + int kx[2]; + for (int ka=0; ka<2; ++ka) + { + if ((ka == 0 && rad1 <= 0.0) || (ka == 1 && rad2 <= 0.0)) + { + kx[ka] = -1; + continue; + } + + RevEngRegion *reg = (ka == 0) ? revedg1->getBlendRegSurf() : + revedg2->getBlendRegSurf(); + shared_ptr<ParamSurface> bsurf = reg->getSurface(0)->surface(); + shared_ptr<ElementarySurface> belem = + dynamic_pointer_cast<ElementarySurface,ParamSurface>(bsurf); + adj_reg[ka] = reg; + adj_surf[ka] = belem; + + double reg_dom[4]; + reg->getDomain(reg_dom); + Point pt3[2]; + int kx1 = (bsurf->instanceType() == Class_Cylinder) ? 0 : 1; + for (int kb=0; kb<2; ++kb) + { + double par[2]; + par[kx1] = 0.5*(reg_dom[2*kx1] + reg_dom[2*kx1+1]); + par[1-kx1] = reg_dom[2*(1-kx1)+kb]; + pt3[kb] = bsurf->point(par[0], par[1]); + } + + double upar1, vpar1, bdist1, upar2, vpar2, bdist2; + Point bclose1, bclose2; + bsurf->closestPoint(pt1, upar1, vpar1, bclose1, bdist1, eps); + bsurf->closestPoint(pt2, upar2, vpar2, bclose2, bdist2, eps); + double uvpar; + if (belem->instanceType() == Class_Cylinder) + uvpar = (bdist1 <= bdist2) ? vpar1 : vpar2; + else + uvpar = (bdist1 <= bdist2) ? upar1 : upar2; + Point tor_pt = (bdist1 <= bdist2) ? pt1 : pt2; + lim[ka] = uvpar; + kx[ka] = (bdist1 <= bdist2) ? 0 : 1; + + // Assume the part of the cylinder to remove is the smaller one + RectDomain bdom = bsurf->containingDomain(); + parbound[4*ka] = bdom.umin(); + parbound[4*ka+1] = bdom.vmin(); + parbound[4*ka+2] = bdom.umax(); + parbound[4*ka+3] = bdom.vmax(); + if (tor_pt.dist(pt3[1]) < tor_pt.dist(pt3[0])) + { + if (belem->instanceType() == Class_Cylinder) + parbound[4*ka+3] = uvpar; + else + parbound[4*ka+2] = uvpar; + upper2[ka] = true; + } + else + { + if (belem->instanceType() == Class_Cylinder) + parbound[4*ka+1] = uvpar; + else + parbound[4*ka] = uvpar; + upper2[ka] = false; + } +#ifdef DEBUG_BLEND + bsurf->writeStandardHeader(of); + bsurf->write(of); +#endif + } + + Point vec1 = (adj_surf[0].get()) ? adj_surf[0]->location() - plane->location() : Point(0.0, 0.0, 0.0); + Point vec2 = (adj_surf[1].get()) ? adj_surf[1]->location() - plane->location() : Point(0.0, 0.0, 0.0); + double sc1 = vec1*dirp; + double sc2 = vec2*dirp; + if (sc1*sc2 < 0.0) //kx[0] == kx[1] && kx[0]>=0) + { + // Need to wait with "setParameterBounds" + vector<RevEngRegion*> blends(3); + blends[0] = adj[jx2]; + blends[1] = revedg1->getBlendRegSurf(); + blends[2] = revedg2->getBlendRegSurf(); + return suitcaseCorner(blends, edges_[ix].get()); + } + else if (possible_suitcase) + return false; // Not an expected configuration + + if (kx[0] == kx[1]) + return false; // Not an expected configuration + + for (int ka=0; ka<2; ++ka) + { + if (adj_surf[ka].get()) + { + adj_surf[ka]->setParameterBounds(parbound[4*ka], parbound[4*ka+1], + parbound[4*ka+2], parbound[4*ka+3]); + adj_reg[ka]->adaptEdges(); + } + } + + // Bound blend cylinder + Point pt3; + torus->point(pt3, 0.5*(dom.umin()+dom.vmin()), 0); + double upar3, vpar3, dist3; + Point close3; + bool upper = false; + cyl->closestPoint(pt3, upar3, vpar3, close3, dist3, eps); + if (fabs(vpar3-dom.vmin()) < fabs(dom.vmax()-vpar3)) + cyl->setParamBoundsV(vpar3, dom.vmax()); + else + { + cyl->setParamBoundsV(dom.vmin(), vpar3); + upper = true; + } + adj[jx2]->adaptEdges(); + + #ifdef DEBUG_BLEND + cyl->writeStandardHeader(of); + cyl->write(of); +#endif + + shared_ptr<Circle> bcircle = cyl->getCircle(vpar3); + shared_ptr<ElementaryCurve> bpar = + cyl->getElementaryParamCurve(bcircle.get(), approx_tol_); + shared_ptr<CurveOnSurface> blendbound(new CurveOnSurface(cyl, bpar, bcircle, + false, 3, 2, vpar3, + (upper) ? 3 : 2, true)); + + // Define traverse boundary edges of torus and adjacent cylinders + vector<shared_ptr<CurveOnSurface> > cylbound(2); + for (int ka=0; ka<2; ++ka) + { + if (!adj_reg[ka]) + continue; + + bool udir = (adj_surf[ka]->instanceType() == Class_Cylinder) ? true : false; + shared_ptr<Circle> circle = torus->getMinorCircle(torlim[ka]); + Point mid(torlim[ka], torlim[2]); + Point vec = Point(torlim[ka],torlim[3]) - Point(torlim[ka],torlim[2]); + vec.normalize(); + shared_ptr<Line> line(new Line(mid, vec)); + line->setParamBounds(0.0, torlim[3]-torlim[2]); + torbound[ka] = + shared_ptr<CurveOnSurface>(new CurveOnSurface(torus, line, circle, + false, 3, 1, torlim[ka], + ka, true)); + vector<shared_ptr<ParamCurve> > tmpcv = + adj_surf[ka]->constParamCurves(lim[ka], udir); + if (tmpcv.size() != 1) + continue; // Should not happen + shared_ptr<ElementaryCurve> space = + dynamic_pointer_cast<ElementaryCurve,ParamCurve>(tmpcv[0]); + shared_ptr<ElementaryCurve> par = + adj_surf[ka]->getElementaryParamCurve(space.get(), approx_tol_); + int bd; + if (udir) + bd = (upper2[ka]) ? 3 : 2; + else + bd = (upper2[ka]) ? 1 : 0; + shared_ptr<ParamCurve> par2; + if (!par.get()) + { + Point pt1(2), pt2(2); + if (udir) + { + pt1[1] = pt2[1] = lim[ka]; + pt1[0] = parbound[4*ka]; + pt2[0] = parbound[4*ka+2]; + } + else + { + pt1[0] = pt2[0] = lim[ka]; + pt1[1] = parbound[4*ka+1]; + pt2[1] = parbound[4*ka+3]; + } + par2 = shared_ptr<ParamCurve>(new SplineCurve(pt1, space->startparam(), + pt2, space->endparam())); + } + cylbound[ka] = + shared_ptr<CurveOnSurface>(new CurveOnSurface(adj_surf[ka], + par.get() ? par : par2, + space, + false, 3, udir ? 1 : 2, + lim[ka], + bd, true)); + } + + // Define planar boundary curve + shared_ptr<CurveOnSurface> planebound; + shared_ptr<ParamCurve> pspace1 = torbound[3]->spaceCurve(); + shared_ptr<Circle> pspace = dynamic_pointer_cast<Circle,ParamCurve>(pspace1); + shared_ptr<ElementaryCurve> ppar = + plane->getElementaryParamCurve(pspace.get(), 10.0*tol2); // Just to test + planebound = shared_ptr<CurveOnSurface>(new CurveOnSurface(plane, ppar, + pspace, false, 1)); + +#ifdef DEBUG_BLEND + std::ofstream ofc("torus_trim.g2"); + for (int ka=0; ka<4; ++ka) + { + if (!torbound[ka].get()) + continue; + shared_ptr<ParamCurve> tmp = torbound[ka]->spaceCurve(); + tmp->writeStandardHeader(ofc); + tmp->write(ofc); + } + for (int ka=0; ka<2; ++ka) + { + if (!cylbound[ka].get()) + continue; + shared_ptr<ParamCurve> tmp = cylbound[ka]->spaceCurve(); + tmp->writeStandardHeader(ofc); + tmp->write(ofc); + } + if (planebound.get()) + { + shared_ptr<ParamCurve> tmp = planebound->spaceCurve(); + tmp->writeStandardHeader(ofc); + tmp->write(ofc); + } + + std::ofstream ofp("torus_par.g2"); + for (int ka=0; ka<4; ++ka) + { + if (!torbound[ka].get()) + continue; + shared_ptr<ParamCurve> tmp = torbound[ka]->parameterCurve(); + if (!tmp.get()) + continue; + SplineDebugUtils::writeSpaceParamCurve(tmp, ofp, 0.0); + } +#endif + + // Move points as appropriate + // From torus + vector<vector<RevEngPoint*> > move1(4); + vector<RevEngPoint*> torus_pts; + for (size_t ki=0; ki<blend_pts.size(); ++ki) + { + if (parvals[2*ki+1] > M_PI) + move1[0].push_back(blend_pts[ki]); // To blend cylinder + else if (parvals[2*ki+1] > pihalf) + move1[1].push_back(blend_pts[ki]); // To plane + else if (parvals[2*ki] < dom.umin()) + move1[2].push_back(blend_pts[ki]); // First adjacent cylinder + else if (parvals[2*ki] > dom.umax()) + move1[3].push_back(blend_pts[ki]); // Second adjacent cylinder + else + { + blend_pts[ki]->setPar(Vector2D(parvals[2*ki],parvals[2*ki+1])); + blend_pts[ki]->setSurfaceDist(dist_ang[ki].first, dist_ang[ki].second); + torus_pts.push_back(blend_pts[ki]); + } + } + + // From blend cylinder + vector<RevEngPoint*> move_cyl; + int num_pts_cyl = adj[jx2]->numPoints(); + for (int ka=0; ka<num_pts_cyl; ++ka) + { + RevEngPoint* curr = adj[jx2]->getPoint(ka); + Vector2D par = curr->getPar(); + if ((upper && par[1] > vpar3) || (upper == false && par[1] < vpar3)) + move_cyl.push_back(curr); + } + + // Remove identified points from cylinder + if (move_cyl.size() > 0) + adj[jx2]->removeAndUpdatePoints(move_cyl); + + // From adjacent cylinders + vector<vector<RevEngPoint*> > move_adj(2); + for (int kb=0; kb<2; ++kb) + { + if (!adj_reg[kb]) + continue; + int num_pts_cyl = adj_reg[kb]->numPoints(); + for (int ka=0; ka<num_pts_cyl; ++ka) + { + RevEngPoint* curr = adj_reg[kb]->getPoint(ka); + Vector2D par = curr->getPar(); + if ((upper2[kb] && par[1] > lim[kb]) || + (upper2[kb] == false && par[1] < lim[kb])) + move_adj[kb].push_back(curr); + } + if (move_adj[kb].size() > 0) + adj_reg[kb]->removeAndUpdatePoints(move_adj[kb]); + } + + // From adjacent plane + vector<RevEngPoint*> move_plane; + adj[jx1]->extractOutOfEdge(planebound, (jx1 == 0) ? intcv1 : intcv2, + radius2, approx_tol_, angtol, move_plane); + + // To plane + bool OK1, OK2, OK3; + if (move1[1].size() > 0) + OK1 = adj[jx1]->addPointsToGroup(move1[1], approx_tol_, angtol); + + // To blend cylinder + if (move1[0].size() > 0) + OK2 = adj[jx2]->addPointsToGroup(move1[0], approx_tol_, angtol); + + // To adjacent cylinders + vector<vector<RevEngPoint*> > added_groups; + for (int ka=0; ka<2; ++ka) + if (move1[2+ka].size() > 0) + { + if (adj_reg[ka]) + OK3 = adj_reg[ka]->addPointsToGroup(move1[2+ka], approx_tol_, angtol); + else + added_groups.push_back(move1[2+ka]); + } + + + // To torus + if (move_plane.size() > 0) + torus_pts.insert(torus_pts.end(), move_plane.begin(), move_plane.end()); + if (move_adj[0].size() > 0) + torus_pts.insert(torus_pts.end(), move_adj[0].begin(), move_adj[0].end()); + if (move_adj[1].size() > 0) + torus_pts.insert(torus_pts.end(), move_adj[1].begin(), move_adj[1].end()); + if (move_cyl.size() > 0) + torus_pts.insert(torus_pts.end(), move_cyl.begin(), move_cyl.end()); + if (torus_pts.size() == 0) + return false; + + // Define torus blend + shared_ptr<RevEngRegion> blendreg(new RevEngRegion(classification_type_, + edge_class_type_, + torus_pts)); + blendreg->setRegionAdjacency(); + regions_.push_back(blendreg); + shared_ptr<HedgeSurface> hedge; + shared_ptr<ParamSurface> torus_tmp = torus; + blendreg->setAssociatedSurface(torus_tmp, approx_tol_, angtol, + min_point_region_, hedge); + if (hedge.get()) + surfaces_.push_back(hedge); + + if (added_groups.size() > 0) + { + vector<HedgeSurface*> dummy_hedge; + surfaceExtractOutput((int)regions_.size()-1, added_groups, dummy_hedge); + } + +#ifdef DEBUG_BLEND + std::ofstream oft("torus_corner.g2"); + blendreg->writeRegionPoints(oft); + adj[jx1]->writeRegionPoints(oft); + adj[jx2]->writeRegionPoints(oft); + if (adj_reg[0]) + adj_reg[0]->writeRegionPoints(oft); + if (adj_reg[1]) + adj_reg[1]->writeRegionPoints(oft); +#endif + + // Add edges to regions + int status = 0; + vector<shared_ptr<ftEdge> > tor_edg(4); + for (int ka=0; ka<4; ++ka) + { + if (torbound[ka].get()) + { + tor_edg[ka] = shared_ptr<ftEdge>(new ftEdge(hedge.get(), torbound[ka], + torbound[ka]->startparam(), + torbound[ka]->endparam())); + blendreg->addTrimEdge(tor_edg[ka]); + } + } + + shared_ptr<ftEdge> plane_edg(new ftEdge(adj[jx1]->getSurface(0), planebound, + planebound->startparam(), + planebound->endparam())); + adj[jx1]->addTrimEdge(plane_edg); + plane_edg->setReversed(true); + tor_edg[3]->connectTwin(plane_edg.get(), status); + + + shared_ptr<ftEdge> cyl_edg(new ftEdge(adj[jx2]->getSurface(0), blendbound, + blendbound->startparam(), + blendbound->endparam())); + adj[jx2]->addTrimEdge(cyl_edg); + cyl_edg->setReversed(true); + tor_edg[2]->connectTwin(cyl_edg.get(), status); + + for (int ka=0; ka<2; ++ka) + { + if (cylbound[ka].get()) + { + shared_ptr<ftEdge> adj_edg(new ftEdge(adj_reg[ka]->getSurface(0), + cylbound[ka], + cylbound[ka]->startparam(), + cylbound[ka]->endparam())); + adj_reg[ka]->addTrimEdge(adj_edg); + adj_edg->setReversed(true); + if (kx[ka] >= 0 && tor_edg[kx[ka]].get()) + tor_edg[kx[ka]]->connectTwin(adj_edg.get(), status); + } + } + + for (size_t ki=0; ki<blend_regs.size(); ++ki) + { + //blend_regs[ki]->removeFromAdjacent(); + blend_regs[ki]->setRemove(); + } + edges_[ix]->clearBlendRegions(); + + return true; +} + +//=========================================================================== +void RevEng::setBlendBoundaries(RevEngRegion *reg) +//=========================================================================== +{ + double eps = 1.0e-6; + if (!reg->hasSurface()) + return; + + shared_ptr<ParamSurface> surf = reg->getSurface(0)->surface(); + if (surf->instanceType() != Class_Cylinder && + surf->instanceType() != Class_Torus) + return; + + double angtol = 5.0*anglim_; + double diag0 = bbox_.low().dist(bbox_.high()); + + // Adjacent regions + RevEngEdge *edge = reg->getBlendEdge(); + RevEngRegion* adj[2]; + edge->getAdjacent(adj[0], adj[1]); + + if ((!adj[0]->hasSurface()) || (!adj[1]->hasSurface())) + return; // Something wrong + + bool out1 = false, out2 = false; + edge->getOuterInfo(out1, out2); + + vector<shared_ptr<CurveOnSurface> > intcv1, intcv2; + edge->getCurve(intcv1, true); + edge->getCurve(intcv2, false); + //double eps1 = approx_tol_; //std::max(1.0e-4, 0.1*approx_tol_); + // for (size_t ki=0; ki<intcv1.size(); ++ki) + // intcv1[ki]->fixMismatchCurves(eps1); + // for (size_t ki=0; ki<intcv2.size(); ++ki) + // intcv2[ki]->fixMismatchCurves(eps1); + +#ifdef DEBUG_BLEND + std::ofstream of("blend.g2"); + reg->writeRegionPoints(of); + surf->writeStandardHeader(of); + surf->write(of); + + adj[0]->writeRegionPoints(of); + adj[1]->writeRegionPoints(of); +#endif + + // Extract longitudial boundary curves + shared_ptr<ElementarySurface> elem = + dynamic_pointer_cast<ElementarySurface,ParamSurface>(surf); + //double radius = elem->radius(0.0, 0.0); + + vector<shared_ptr<ElementarySurface> > adj_elem(2); + for (int ka=0; ka<2; ++ka) + { + shared_ptr<ParamSurface> tmp = adj[ka]->getSurface(0)->surface(); + adj_elem[ka] = dynamic_pointer_cast<ElementarySurface,ParamSurface>(tmp); + } + +#ifdef DEBUG_BLEND + std::ofstream ofsf("adj_sfs.g2"); + adj_elem[0]->writeStandardHeader(ofsf); + adj_elem[0]->write(ofsf); + shared_ptr<ParamCurve> tmp_cv1 = intcv1[0]->spaceCurve(); + tmp_cv1->writeStandardHeader(ofsf); + tmp_cv1->write(ofsf); + adj_elem[1]->writeStandardHeader(ofsf); + adj_elem[1]->write(ofsf); + shared_ptr<ParamCurve> tmp_cv2 = intcv2[0]->spaceCurve(); + tmp_cv2->writeStandardHeader(ofsf); + tmp_cv2->write(ofsf); +#endif + + Point posi1, posi2, pos; + intcv1[0]->point(posi1, intcv1[0]->startparam()); + double pari = (edge->isClosed(approx_tol_)) ? + 0.5*(intcv1[0]->startparam() + intcv1[intcv1.size()-1]->endparam()) : + intcv1[intcv1.size()-1]->endparam(); + intcv1[intcv1.size()-1]->point(posi2, pari); + pos = 0.5*(posi1 + posi2); + RectDomain surfdom = surf->containingDomain(); + double regdom[4]; + reg->getDomain(regdom); + double regfac = 2.0; + double rad; + double tpar1, tpar2; + bool udir; + int constdir; + double delfac = 0.6; + double seamfac = 0.1; + bool plane1 = (adj_elem[0]->instanceType() == Class_Plane); + bool plane2 = (adj_elem[1]->instanceType() == Class_Plane); + if (surf->instanceType() == Class_Cylinder) + { + Point norm1 = adj_elem[0]->direction(); + Point norm2 = adj_elem[1]->direction(); + double ang = norm1.angle(norm2); + ang = std::min(ang, M_PI-ang); + + tpar1 = M_PI - 0.5*ang; + tpar2 = tpar1 + ang; + shared_ptr<Cylinder> cyl = dynamic_pointer_cast<Cylinder,ParamSurface>(surf); + cyl->setParamBoundsU(tpar1, tpar2); + double tdelreg = regdom[3] - regdom[2]; + if (tdelreg < regfac*approx_tol_) + tdelreg = 0.5*diag0; + if (surfdom.vmax() - surfdom.vmin() > regfac*tdelreg) + cyl->setParamBoundsV(std::max(surfdom.vmin(), regdom[2]-delfac*tdelreg), + std::min(surfdom.vmax(), regdom[3]+delfac*tdelreg)); + rad = cyl->getRadius(); + udir = false; + constdir = 0; + } + else + { + shared_ptr<Torus> tor = dynamic_pointer_cast<Torus,ParamSurface>(surf); + RectDomain tor_dom = tor->getParameterBounds(); + if (plane1 || plane2) + { + int plane_ix = (plane1) ? 0 : 1; + if (adj_elem[plane_ix]->instanceType() != Class_Plane) + return; // Not as expected + rad = tor->getMinorRadius(); + bool plane_out = (plane_ix == 0) ? out1 : out2; + bool rot_out = (plane_ix == 0) ? out2 : out1; + double phi = 0.5*M_PI; + Point norm = adj_elem[plane_ix]->direction(); + Point norm2 = adj[plane_ix]->getMeanNormalTriang(); + double beta = 0.5; //(norm*norm2 > 0.0) ? 0.5 : 0.0; + if (adj_elem[1-plane_ix]->instanceType() == Class_Cone) + { + shared_ptr<Cone> cone = + dynamic_pointer_cast<Cone,ElementarySurface>(adj_elem[1-plane_ix]); + double alpha = cone->getConeAngle(); + Point axis = adj_elem[1-plane_ix]->direction(); + int sgn = (norm*axis < 0.0) ? -1 : 1; + phi += sgn*alpha; + } + if (rot_out) + { + tpar2 = tor_dom.vmin()+(1.0+beta)*M_PI; + tpar1 = tpar2 - phi; + } + else + { + tpar1 = tor_dom.vmin()+(1.0-beta)*M_PI; + tpar2 = tpar1 + phi; + } + if (plane_out) + { + int sgn = 1; //(norm*norm2 < 0.0 && rot_out == false) ? -1 : 1; + tpar1 += 0.5*sgn*M_PI; + tpar2 += 0.5*sgn*M_PI; + } + } + else + { + int cyl_ix = (adj_elem[0]->instanceType() == Class_Cylinder) ? 0 : 1; + int cone_ix = 1 - cyl_ix; + if (adj_elem[cyl_ix]->instanceType() != Class_Cylinder || + adj_elem[cone_ix]->instanceType() != Class_Cone) + return; + + shared_ptr<Cone> cone = + dynamic_pointer_cast<Cone,ElementarySurface>(adj_elem[cone_ix]); + double alpha = cone->getConeAngle(); + double beta = M_PI - fabs(alpha); + double phi = 0.5*(M_PI - beta); + rad = tor->getMinorRadius(); + Point axis = adj_elem[cyl_ix]->direction(); + Point loc = adj_elem[cyl_ix]->location(); + double rd = (pos-loc)*axis; + Point centr = loc + rd*axis; + Point loc2 = tor->location(); + Point loc2_2 = centr + ((loc2 - centr)*axis)*axis; + double hh = loc2_2.dist(centr); + double d2 = hh/sin(phi) - rad; + double xlen = sqrt((rad+d2)*(rad+d2) - rad*rad); + tpar1 = tor_dom.vmin() + M_PI - 2.0*xlen; + tpar2 = tpar1 + 2*xlen; + } + + double tdelreg = regdom[1] - regdom[0]; + double upar1 = tor_dom.umin(); + double upar2 = tor_dom.umax(); + double umid = 0.5*(regdom[0]+regdom[1]); + double eps2 = std::max(eps, 0.001*(upar2-upar1)); + + double cp1, cp2; + Point cpos1, cpos2; + double seed[2]; + seed[0] = 0.5*(regdom[0]+regdom[1]); + seed[1] = 0.5*(regdom[2]+regdom[3]); + int seam1 = edge->closedSfAtEnd(approx_tol_, cp1, cpos1, true); + int seam2 = edge->closedSfAtEnd(approx_tol_, cp2, cpos2, false); + double dd = cpos1.dist(cpos2); + double u1, v1, u2, v2, d1, d2; + Point cl1, cl2; + elem->closestPoint(cpos1, u1, v1, cl1, d1, eps, 0, seed); + elem->closestPoint(cpos2, u2, v2, cl2, d2, eps, 0, seed); + if (u2 < u1) + std::swap(u1, u2); + if ((u2-u1 < tdelreg-eps || umid > u2 || umid < u1) && (seam1 || seam2)) + { + // Check parameter at seam + if (seam1 && u1-upar1 < eps2) + u1 = upar2; + else if (seam2 && upar2-u2 < eps2) + u2 = upar1; + if (u2 < u1) + std::swap(u1, u2); + } + + if (seam1 != seam2 && dd > approx_tol_) + { + bool close1, close2; + tor->isClosed(close1, close2); // Expects close1 = true + if (close1) + { + if (tdelreg > u2-u1) + { + int stop_seam = 1; + } + + // Check for seam. Solution could be improved + if (fabs(u1-upar1) < eps2 && umid > u2) // && upar2 < u2) + u1 = upar2; + else if (fabs(upar2-u1) < eps2 && umid < u2) + u1 = upar1; + if (fabs(u2-upar1) < eps2 && umid > u1) + u2 = upar2; + else if (fabs(upar2-u2) < eps2 && umid < u1) // && upar1 > u1) + u2 = upar1; + + if (u2 < u1) + std::swap(u1, u2); + } + + upar1 = std::max(upar1, u1); + upar2 = std::min(upar2, u2); + } + + if (upar2 - upar1 > regfac*tdelreg) + { + upar1 = std::max(upar1, std::min(regdom[0]-delfac*tdelreg, u1)); + upar2 = std::min(upar2, std::max(regdom[1]+delfac*tdelreg, u2)); + if (upar1 < seamfac) + upar1 = 0.0; + if (2*M_PI-upar2 < seamfac) + upar2 = 2*M_PI; + } + tor->setParameterBounds(upar1, tpar1, upar2, tpar2); + udir = true; + constdir = 1; + } + + + vector<shared_ptr<ParamCurve> > bdcv1 = elem->constParamCurves(tpar1, udir); + vector<shared_ptr<ParamCurve> > bdcv2 = elem->constParamCurves(tpar2, udir); + if (bdcv1.size() != 1 || bdcv2.size() != 1) + return; // Something strange + + shared_ptr<ElementaryCurve> space[2]; + space[0] = dynamic_pointer_cast<ElementaryCurve,ParamCurve>(bdcv1[0]); + space[1] = dynamic_pointer_cast<ElementaryCurve,ParamCurve>(bdcv2[0]); + if ((!space[0].get()) || (!space[1].get())) + return; + BoundingBox bb1 = adj[0]->getBbox(); + BoundingBox bb2 = adj[1]->getBbox(); + double diag = std::min(bb1.low().dist(bb1.high()), bb2.low().dist(bb2.high())); + if (constdir == 0 && (space[0]->startparam() < -0.5*diag || + space[0]->endparam() > 0.5*diag)) + { + for (int ka=0; ka<2; ++ka) + space[ka]->setParamBounds(std::max(space[0]->startparam(), -0.5*diag), + std::min(space[0]->endparam(), 0.5*diag)); + } + +#ifdef DEBUG_BLEND + space[0]->writeStandardHeader(of); + space[0]->write(of); + space[1]->writeStandardHeader(of); + space[1]->write(of); +#endif + RectDomain dom = elem->getParameterBounds(); + Point parpt1(dom.umin(), dom.vmin()), parpt2(dom.umin(), dom.vmax()); + Point parpt3(dom.umax(), dom.vmin()), parpt4(dom.umax(), dom.vmax()); + Point lpos1 = (udir) ? Point(0.0, dom.vmin()) : Point(dom.umin(), 0.0); + Point lpos2 = (udir) ? Point(0.0, dom.vmax()) : Point(dom.umax(), 0.0); + Point pvec = (udir) ? Point(1.0, 0.0) : Point(0.0, 1.0); + + double t1 = space[0]->startparam(); + double t2 = space[0]->endparam(); + shared_ptr<ElementaryCurve> par1(new Line(lpos1, pvec)); + par1->setParamBounds(t1, t2); + shared_ptr<ElementaryCurve> par2(new Line(lpos2, pvec)); + par2->setParamBounds(t1, t2); +#ifdef DEBUG_BLEND + // Check + double tm1 = 0.75*t1 + 0.25*t2; + double tm2 = 0.25*t1 + 0.75*t2; + Point pp1, pp2, pp3, pp4; + Point sp1, sp2, sp3, sp4; + Point ssp1, ssp2, ssp3, ssp4; + space[0]->point(sp1, tm1); + space[0]->point(sp2, tm2); + space[1]->point(sp3, tm1); + space[1]->point(sp4, tm2); + par1->point(pp1, tm1); + par1->point(pp2, tm2); + par2->point(pp3, tm1); + par2->point(pp4, tm2); + surf->point(ssp1, pp1[0], pp1[1]); + surf->point(ssp2, pp2[0], pp2[1]); + surf->point(ssp3, pp3[0], pp3[1]); + surf->point(ssp4, pp4[0], pp4[1]); +#endif + + shared_ptr<ElementaryCurve> adj_par[2]; + Point close1, close2; + double upar1, upar2, vpar1, vpar2, dist1, dist2; + Point pos1, pos2; + int ix[2]; + ix[0] = 0; + ix[1] = 1; + + // Check for curve matching + space[0]->point(pos1, t1); + adj_elem[0]->closestPoint(pos1, upar1, vpar1, close1, dist1, eps); + adj_elem[1]->closestPoint(pos1, upar2, vpar2, close2, dist2, eps); + if (dist2 < dist1) + std::swap(ix[0], ix[1]); + + double tol5 = 5.0*approx_tol_; + for (int ka=0; ka<2; ++ka) + { + adj_par[ix[ka]] = adj_elem[ix[ka]]->getElementaryParamCurve(space[ka].get(), + tol5); + if (!adj_par[ix[ka]].get()) + { + std::cout << "No parameter curve found" << std::endl; + } + + // space[ka]->point(pos1, t1); + // space[ka]->point(pos2, t2); + // adj_elem[ix[ka]]->closestPoint(pos1, upar1, vpar1, close1, dist1, eps); + // adj_elem[ix[ka]]->closestPoint(pos2, upar2, vpar2, close2, dist2, eps); + // Point pp1(upar1,vpar1), pp2(upar2,vpar2); + // Point mpar = (t2*pp1 -t1*pp2)/(t2-t1); + // Point mvec = pp2 - pp1; + // mvec.normalize(); + + // adj_par[ix[ka]] = shared_ptr<ElementaryCurve>(new Line(mpar, mvec)); + // adj_par[ix[ka]]->setParamBounds(t1, t2); + } + + // Create edges. Orientation in adjacent regions is not set + int status = 0; + vector<shared_ptr<ftEdge> > bdedg(2); + shared_ptr<CurveOnSurface> sfcv1(new CurveOnSurface(elem, par1, space[0], false, 3, + constdir+1, tpar1, 2*constdir, true)); + bdedg[0] = shared_ptr<ftEdge>(new ftEdge(reg->getSurface(0), sfcv1, t1, t2)); +#ifdef DEBUG_BLEND + bool same_orient = sfcv1->sameOrientation(); + bool same_trace = sfcv1->sameTrace(approx_tol_); + bool same_cv = sfcv1->sameCurve(approx_tol_); + if ((!same_orient) || (!same_trace) || (!same_cv)) + std::cout << "Surface curve 1 mismatch " << same_orient << " " << same_trace << " " << same_cv << std::endl; +#endif + shared_ptr<CurveOnSurface> sfcv2(new CurveOnSurface(elem, par2, space[1], false, 3, + constdir+1, tpar2, 2*constdir+1, true)); + //sfcv2->reverseParameterDirection(); + bdedg[1] = shared_ptr<ftEdge>(new ftEdge(reg->getSurface(0), sfcv2, t1, t2)); +#ifdef DEBUG_BLEND + same_orient = sfcv2->sameOrientation(); + same_trace = sfcv2->sameTrace(approx_tol_); + same_cv = sfcv2->sameCurve(approx_tol_); + if ((!same_orient) || (!same_trace) || (!same_cv)) + std::cout << "Surface curve 2 mismatch " << same_orient << " " << same_trace << " " << same_cv << std::endl; +#endif + reg->addTrimEdge(bdedg[0]); + reg->addTrimEdge(bdedg[1]); + + shared_ptr<CurveOnSurface> adj_sfcv[2]; + shared_ptr<ftEdge> adj_edg[2]; + vector<RevEngPoint*> out[2]; + for (int ka=0; ka<2; ++ka) + { + adj_sfcv[ix[ka]] = shared_ptr<CurveOnSurface>(new CurveOnSurface(adj_elem[ix[ka]], + adj_par[ix[ka]], + space[ka], + false, 1)); + // if (!adj_sfcv[ix[ka]]->hasParameterCurve()) + // { + // vector<shared_ptr<CurveOnSurface> > tmp_cvs; + // tmp_cvs.push_back(adj_sfcv[ix[ka]]); + // vector<pair<double,double> > t1_t2; + // adj[ix[ka]]->getCurveRestriction(tmp_cvs, approx_tol_, anglim_, t1_t2); + // if (t1_t2.size() == 1) + // { + // if (t1_t2[0].first > adj_sfcv[ix[ka]]->startparam() || + // t1_t2[0].second < adj_sfcv[ix[ka]]->endparam()) + // { + // } + // } + // } + adj_edg[ix[ka]] = shared_ptr<ftEdge>(new ftEdge(adj[ix[ka]]->getSurface(0), + adj_sfcv[ix[ka]], t1, t2)); + + adj[ix[ka]]->addTrimEdge(adj_edg[ix[ka]]); + bdedg[ka]->setReversed(true); + adj_edg[ix[ka]]->connectTwin(bdedg[ka].get(), status); + + // Identify points from the adjacent regions lying outside the corresponding + // trimming curve + adj[ix[ka]]->extractOutOfEdge(adj_sfcv[ix[ka]], + (ix[ka] == 0) ? intcv1 : intcv2, + rad, approx_tol_, angtol, out[ix[ka]]); + } + +#ifdef DEBUG_BLEND + std::ofstream of2("out_points.g2"); + for (int ka=0; ka<2; ++ka) + { + if (out[ka].size() > 0) + { + of2 << "400 1 0 4 0 255 0 255" << std::endl; + of2 << out[ka].size() << std::endl; + for (size_t kr=0; kr<out[ka].size(); ++kr) + of2 << out[ka][kr]->getPoint() << std::endl; + } + } +#endif + + + // Add out-points to the blend regions. + // NB! This can be too simple in a more complex configuration. + // Let's wait for the problem to turn up + if (out[0].size() > 0 || out[1].size() > 0) + { + vector<RevEngPoint*> points; + for (int ka=0; ka<2; ++ka) + if (out[ka].size() > 0) + points.insert(points.end(), out[ka].begin(), out[ka].end()); + bool integrated = reg->addPointsToGroup(points, approx_tol_, angtol); + if (!integrated) + { + vector<HedgeSurface*> dummy_sfs; + vector<RevEngPoint*> dummy_pts; + for (int ka=0; ka<2; ++ka) + { + if (out[ix[ka]].size() > 0) + { + vector<vector<RevEngPoint*> > out_1; + adj[ix[ka]]->connectedGroups(out[ix[ka]], out_1, false, dummy_pts); + for (size_t kr=0; kr<regions_.size(); ++kr) + if (regions_[kr].get() == adj[ix[ka]]) + { + surfaceExtractOutput((int)kr, out_1, dummy_sfs); + break; + } + } + } + } + } + + // Identify points associated to the blend region that should be + // moved to the adjacent regions + vector<int> adj_ix(4); + adj_ix[0] = 3; + adj_ix[1] = 1; + adj_ix[2] = 0; + adj_ix[3] = 2; + vector<vector<RevEngPoint*> > move2adj(4); + vector<RevEngPoint*> remain; + vector<RevEngPoint*> regpoints = reg->getPoints(); + extractOutPoints(regpoints, elem, adj_ix, approx_tol_, angtol, + move2adj, remain); + +#ifdef DEBUG_BLEND + std::ofstream of2_3("in_points.g2"); + for (int ka=0; ka<4; ++ka) + { + if (move2adj[ka].size() > 0) + { + of2_3 << "400 1 0 4 100 155 0 255" << std::endl; + of2_3 << move2adj[ka].size() << std::endl; + for (size_t kr=0; kr<move2adj[ka].size(); ++kr) + of2_3 << move2adj[ka][kr]->getPoint() << std::endl; + } + } +#endif + + int kx = 2*(1-constdir); + for (int ka=kx; ka<=kx+1; ++ka) + { + if (move2adj[ka].size() > 0) + { + remain.insert(remain.end(), move2adj[ka].begin(), move2adj[ka].end()); + move2adj[ka].clear(); + } + } + + for (int ka=0; ka<=1; ++ka) + { + int kb = 2*constdir+ka; + if (move2adj[kb].size() > 0) + { + reg->removePoints(move2adj[kb]); + bool integrated = adj[ix[ka]]->addPointsToGroup(move2adj[kb], + approx_tol_, angtol); + if (!integrated) + MESSAGE("RevEng::setBlendBoundaris. Missing adjacent surface"); + } + } + +#ifdef DEBUG_BLEND + std::ofstream of3("updated_blend.g2"); + reg->writeRegionPoints(of3); + adj[0]->writeRegionPoints(of3); + adj[1]->writeRegionPoints(of3); +#endif + int stop_break = 1; +} + +//=========================================================================== + +// Service functionality for suitcaseCorner + +bool getBlendRegMatches(vector<RevEngRegion*>& adj_blends, + vector<vector<shared_ptr<ftEdge> > >& trim_edgs, + vector<vector<pair<double, double> > >& par_lim, + vector<vector<size_t> >& match) +{ +#ifdef DEBUG_BLEND + std::ofstream of("int_pt.g2"); +#endif + for (size_t ki=0; ki<adj_blends.size(); ++ki) + for (size_t kj=ki+1; kj<adj_blends.size(); ++kj) + { + size_t kr, kh; + for (kr=0; kr<trim_edgs[ki].size(); ++kr) + { + ftEdgeBase *edg1 = trim_edgs[ki][kr]->twin(); + ftFaceBase *face1 = (edg1->geomEdge()) ? + edg1->geomEdge()->face() : 0; + if (!face1) + return false; + for (kh=0; kh<trim_edgs[kj].size(); ++kh) + { + ftEdgeBase *edg2 = trim_edgs[kj][kh]->twin(); + ftFaceBase *face2 = (edg2->geomEdge()) ? + edg2->geomEdge()->face() : 0; + if (!face2) + return false; + if (face1 == face2) + break; + } + if (kh < trim_edgs[kj].size()) + break; + } + if (kr == trim_edgs[ki].size() || kh == trim_edgs[kj].size()) + continue; + + shared_ptr<ParamCurve> cv1 = trim_edgs[ki][kr]->geomCurve(); + shared_ptr<ParamCurve> cv2 = trim_edgs[kj][kh]->geomCurve(); + double par1, par2, dist; + Point ptc1, ptc2; + ClosestPoint::closestPtCurves(cv1.get(), cv2.get(), par1, par2, + dist, ptc1, ptc2); +#ifdef DEBUG_BLEND + of << "400 1 0 4 155 100 0 255" << std::endl; + of << "1" << std::endl; + of << ptc1 << std::endl; + of << "400 1 0 4 155 100 0 255" << std::endl; + of << "1" << std::endl; + of << ptc2 << std::endl; +#endif + par_lim[ki][kr] = std::make_pair(par1, dist); + par_lim[kj][kh] = std::make_pair(par2, dist); + vector<size_t> match0{ki, kr, kj, kh}; + match.push_back(match0); + } + return true; +} + + +bool getTrimEdgeMidpoint(vector<vector<shared_ptr<ftEdge> > >& trim_edgs, + vector<vector<pair<double, double> > >& par_lim, + vector<vector<pair<double, double> > >& midp) +{ + for (size_t ki=0; ki<par_lim.size(); ++ki) + { + int num = 0; + double par = 0.0; + for (size_t kj=0; kj<par_lim[ki].size(); ++kj) + if (par_lim[ki][kj].second >= 0.0) + { + par += par_lim[ki][kj].first; + ++num; + } + if (num != 2) + return false; + par /= (double)num; + midp[ki].resize(par_lim[ki].size()); + for (size_t kj=0; kj<par_lim[ki].size(); ++kj) + { + if (par_lim[ki][kj].second < 0.0) + { + midp[ki][kj] = std::make_pair(0.0, -1.0); + continue; + } + shared_ptr<ParamCurve> cv = trim_edgs[ki][kj]->geomCurve(); + Point pt1 = cv->point(par_lim[ki][kj].first); + Point pt2 = cv->point(par); + double dist = pt1.dist(pt2); + midp[ki][kj] = std::make_pair(par,dist); + //int stop_break = 1; + } + } + return true; +} + +bool computeCornerBoundaryCurves(vector<RevEngRegion*>& adj_blends, + vector<vector<shared_ptr<ftEdge> > >& trim_edgs, + vector<vector<pair<double, double> > >& par_lim, + vector<vector<pair<double, double> > >& midp, + vector<vector<size_t> >& match, double tol, + vector<shared_ptr<CurveOnSurface> >& blend_bd, + vector<RevEngRegion*>& adjreg) +{ + double tol1 = 0.5*tol; + + // Want four boundary curves if possible + vector<double> midd(midp.size()); + for (size_t ki=0; ki<midp.size(); ++ki) + { + double middist = 0.0; + for (size_t kj=0; kj<midp[ki].size(); ++kj) + middist = std::max(middist, midp[ki][kj].second); + midd[ki] = middist; + } + vector<double> midd2(midd.begin(), midd.end()); + + std::sort(midd2.begin(), midd2.end()); + double tol2; + if (midd2.size() > 4 && midd2.size() < 2) + return false; // Currently not handled + else if (midd2.size() == 4) + tol2 = 2.0*midd2[3]; + else if (midd2.size() == 2) + tol2 = tol1; + else + tol2 = 0.5*(midd2[0] + midd2[1]); + + adjreg.insert(adjreg.end(), adj_blends.begin(), adj_blends.end()); + + vector<pair<double,double> > cvpar(adj_blends.size()); + vector<bool> parset(adj_blends.size(), false); + + // Start defining iso-parametric curves due to close intersection points + for (size_t ki=0; ki<adj_blends.size(); ++ki) + { + if (midd[ki] <= tol1) + { + double par; + size_t kj; + for (kj=0; kj<midp[ki].size() && midp[ki][kj].second < 0.0; ++kj); + par = midp[ki][kj].first; + cvpar[ki] = std::make_pair(par, par); + parset[ki] = true; + } + } + + // Continue with straight curve between opposite intersection points + for (size_t ki=0; ki<adj_blends.size(); ++ki) + { + if (midd[ki] <= tol2) + { + double par1, par2; + size_t kj, kr; + for (kj=0; kj<par_lim[ki].size() && par_lim[ki][kj].second < 0.0; ++kj); + par1 = par_lim[ki][kj].first; + for (kr=kj+1; kr<par_lim[ki].size() && par_lim[ki][kr].second < 0.0; ++kr); + par2 = par_lim[ki][kr].first; + cvpar[ki] = std::make_pair(par1, par2); + parset[ki] = true; + } + } + + if (adj_blends.size() != 3) + return false; // Waiting for a test case + + // Set iso-curve parameters for adjacent blends + size_t kj; + vector<pair<size_t, size_t> > missing; + vector<double> div_par; + for (kj=0; kj<parset.size(); ++kj) + { + if (parset[kj]) + { + size_t kh, kr; + for (kh=0; kh<par_lim[kj].size() && par_lim[kj][kh].second < 0.0; ++kh); + for (kr=kh+1; kr<par_lim[kj].size() && par_lim[kj][kr].second < 0.0; ++kr); + + int ix1=-1, ix2=-1; + double par1, par2; + for (size_t kv=0; kv<match.size(); ++kv) + { + if (match[kv][0] == kj) + { + if (match[kv][1] == kh) + { + ix1 = (int)match[kv][2]; + par1 = par_lim[ix1][match[kv][3]].first; + missing.push_back(std::make_pair(match[kv][2], 1-match[kv][3])); + div_par.push_back(par1); + } + else if (match[kv][1] == kr) + { + ix2 = (int)match[kv][2]; + par2 = par_lim[ix2][match[kv][3]].first; + missing.push_back(std::make_pair(match[kv][2], 1-match[kv][3])); + div_par.push_back(par2); + } + } + else if (match[kv][2] == kj) + { + if (match[kv][3] == kh) + { + ix1 = (int)match[kv][0]; + par1 = par_lim[ix1][match[kv][1]].first; + missing.push_back(std::make_pair(match[kv][0], 1-match[kv][1])); + div_par.push_back(par1); + } + else if (match[kv][3] == kr) + { + ix2 = (int)match[kv][0]; + par2 = par_lim[ix2][match[kv][1]].first; + missing.push_back(std::make_pair(match[kv][0], 1-match[kv][1])); + div_par.push_back(par2); + } + } + } + if (ix1 < 0 || ix2 < 0) + return false; + cvpar[ix1] = std::make_pair(par1, par1); + parset[ix1] = true; + cvpar[ix2] = std::make_pair(par2, par2); + parset[ix2] = true; + break; + } + } + if (kj == parset.size()) + return false; + + double eps = 1.0e-9; + for (size_t ki=0; ki<adj_blends.size(); ++ki) + { + if (!parset[ki]) + return false; // Missing information + if (fabs(cvpar[ki].first-cvpar[ki].second) < eps) + { + // Iso-parametric curve + size_t kj; + for (kj=0; kj<midp[ki].size() && midp[ki][kj].second < 0.0; ++kj); + double par = 0.5*(cvpar[ki].first+cvpar[ki].second); + shared_ptr<ParamCurve> cv = trim_edgs[ki][kj]->geomCurve(); + shared_ptr<CurveOnSurface> sfcv = + dynamic_pointer_cast<CurveOnSurface,ParamCurve>(cv); + shared_ptr<ParamCurve> pcv = sfcv->parameterCurve(); + shared_ptr<ParamSurface> surf = sfcv->underlyingSurface(); + if ((!pcv.get()) || (!surf.get())) + return false; + double val; + int dir; + bool isconst = sfcv->isConstantCurve(tol1, dir, val); + if (!isconst) + return false; + RectDomain dom = surf->containingDomain(); + double pmin = (dir == 1) ? dom.umin() : dom.vmin(); + double pmax = (dir == 1) ? dom.umax() : dom.vmax(); + shared_ptr<CurveOnSurface> sfcv2(new CurveOnSurface(surf, (3-dir), + par, pmin, pmax, + -1)); + blend_bd.push_back(sfcv2); + } + else + { + // Straight curve in the parameter domain + size_t kj, kr; + for (kj=0; kj<par_lim[ki].size() && par_lim[ki][kj].second < 0.0; ++kj); + for (kr=kj+1; kr<par_lim[ki].size() && par_lim[ki][kr].second < 0.0; +kr); + double par1 = cvpar[ki].first; + double par2 = cvpar[ki].second; + shared_ptr<ParamCurve> cv1 = trim_edgs[ki][kj]->geomCurve(); + shared_ptr<ParamCurve> cv2 = trim_edgs[ki][kr]->geomCurve(); + shared_ptr<CurveOnSurface> sfcv1 = + dynamic_pointer_cast<CurveOnSurface,ParamCurve>(cv1); + shared_ptr<CurveOnSurface> sfcv2 = + dynamic_pointer_cast<CurveOnSurface,ParamCurve>(cv2); + shared_ptr<ParamCurve> pcv1 = sfcv1->parameterCurve(); + shared_ptr<ParamCurve> pcv2 = sfcv2->parameterCurve(); + if ((!pcv1.get()) || (!pcv2.get())) + return false; + Point ppt1 = pcv1->point(par1); + Point ppt2 = pcv2->point(par2); + shared_ptr<SplineCurve> pcv3(new SplineCurve(ppt1, ppt2)); + shared_ptr<CurveOnSurface> sfcv3(new CurveOnSurface(sfcv1->underlyingSurface(), + pcv3, true)); + bool space = sfcv3->ensureSpaceCrvExistence(tol1); + if (!space) + return false; + blend_bd.push_back(sfcv3); + } + } + +#ifdef DEBUG_BLEND + std::ofstream of1("space_bd.g2"); + for (size_t kr=0; kr<blend_bd.size(); ++kr) + { + shared_ptr<ParamCurve> space = blend_bd[kr]->spaceCurve(); + shared_ptr<ParamCurve> parcv = blend_bd[kr]->parameterCurve(); + space->writeStandardHeader(of1); + space->write(of1); + } +#endif + + if (missing.size() > 0) + { + // Add remaining curves + size_t ki, kj; + for (ki=0; ki<missing.size(); ++ki) + for (kj=ki+1; kj<missing.size(); ++kj) + { + size_t kr; + for (kr=0; kr<match.size(); ++kr) + if (missing[ki].first == match[kr][0] && + missing[ki].second == match[kr][1] && + missing[kj].first == match[kr][2] && + missing[kj].second == match[kr][3]) + break; + if (kr == match.size()) + continue; // Should not happen + size_t ki1 = missing[ki].first, kr1 = missing[ki].second; + size_t kj1 = missing[kj].first, kh1 = missing[kj].second; + ftEdgeBase *edg = trim_edgs[ki1][kr1]->twin(); + ftSurface *face = edg->geomEdge()->face()->asFtSurface(); + if (!face) + continue; + shared_ptr<ParamSurface> surf = face->surface(); + shared_ptr<ParamCurve> cv1 = trim_edgs[ki1][kr1]->geomCurve(); + shared_ptr<ParamCurve> cv2 = trim_edgs[kj1][kh1]->geomCurve(); + vector<Point> der1(2), der2(2); + cv1->point(der1, div_par[ki], 1); + cv2->point(der2, div_par[kj], 1); + double dd = der1[0].dist(der2[0]); + der1[1].normalize(); + der2[1].normalize(); + if ((der2[0]-der1[0])*der1[1] < 0.0) + der1[1] *= -1; + if ((der2[0]-der1[0])*der2[1] < 0.0) + der2[1] *= -1; +#ifdef DEBUG_BLEND + std::ofstream of3("missing_cvs.g2"); + of3 << "400 1 0 4 255 0 0 255" << std::endl; + of3 << "1" << std::endl; + of3 << der1[0] << std::endl; + of3 << "410 1 0 4 255 0 0 255" << std::endl; + of3 << "1" << std::endl; + of3 << der1[0] << " " << der1[0]+0.3*dd*der1[1] << std::endl; + of3 << "400 1 0 4 255 0 0 255" << std::endl; + of3 << "1" << std::endl; + of3 << der2[0] << std::endl; + of3 << "410 1 0 4 255 0 0 255" << std::endl; + of3 << "1" << std::endl; + of3 << der2[0] << " " << der2[0]+0.3*dd*der2[1] << std::endl; +#endif + vector<double> knots(8, 0.0); + for (int ka=0; ka<4; ++ka) + knots[4+ka] = dd; + dd /= 3.0; + vector<double> coefs; + coefs.insert(coefs.end(), der1[0].begin(), der1[0].end()); + Point cf1 = der1[0] + dd*der1[1]; + coefs.insert(coefs.end(), cf1.begin(), cf1.end()); + Point cf2 = der2[0] - dd*der2[1]; + coefs.insert(coefs.end(), cf2.begin(), cf2.end()); + coefs.insert(coefs.end(), der2[0].begin(), der2[0].end()); + shared_ptr<ParamCurve> mcv(new SplineCurve(4, 4, &knots[0], + &coefs[0], 3)); +#ifdef DEBUG_BLEND + mcv->writeStandardHeader(of3); + mcv->write(of3); + surf->writeStandardHeader(of3); + surf->write(of3); +#endif + + shared_ptr<SplineCurve> space_proj, par_proj; + CurveCreators::projectCurve(mcv, surf, tol1, space_proj, + par_proj); + + shared_ptr<CurveOnSurface> sfcv_proj(new CurveOnSurface(surf, + par_proj, + space_proj, + true, 1)); +#ifdef DEBUG_BLEND + space_proj->writeStandardHeader(of3); + space_proj->write(of3); +#endif + blend_bd.push_back(sfcv_proj); + HedgeSurface *regface = dynamic_cast<HedgeSurface*>(face); + if (!regface) + return false; + adjreg.push_back(regface->getRegion(0)); + } + } + return true; +} + +bool getCoonsBoundaryInfo(vector<shared_ptr<CurveOnSurface> >& blend_bd, + double tol, + vector<shared_ptr<ParamCurve> >& bdcvs, + vector<shared_ptr<ParamCurve> >& crosscvs) +{ + bdcvs.resize(blend_bd.size()); + crosscvs.resize(blend_bd.size()); + + for (size_t ki=0; ki<blend_bd.size(); ++ki) + { + shared_ptr<ParamCurve> tmp_cv(blend_bd[ki]->spaceCurve()->clone()); + if (tmp_cv->instanceType() == Class_Circle) + { + shared_ptr<Circle> circ = dynamic_pointer_cast<Circle,ParamCurve>(tmp_cv); + bdcvs[ki] = shared_ptr<SplineCurve>(circ->createNonRationalSpline(tol)); + } + else if (tmp_cv->instanceType() == Class_Line) + { + shared_ptr<Line> line = dynamic_pointer_cast<Line,ParamCurve>(tmp_cv); + bdcvs[ki] = shared_ptr<SplineCurve>(line->createSplineCurve()); + } + else if (tmp_cv->instanceType() == Class_SplineCurve) + { + shared_ptr<SplineCurve> cv = dynamic_pointer_cast<SplineCurve,ParamCurve>(tmp_cv); + if (cv->rational()) + { + shared_ptr<ParamCurve> tmp_par = blend_bd[ki]->parameterCurve(); + shared_ptr<ParamSurface> tmp_sf = blend_bd[ki]->underlyingSurface(); + bdcvs[ki] = + shared_ptr<SplineCurve>(CurveCreators::liftParameterCurve(tmp_par, + tmp_sf, + tol)); + } + else + bdcvs[ki] = tmp_cv; + } + else + return false; + shared_ptr<CurveOnSurface> tmp_sfcv(blend_bd[ki]->clone()); + tmp_sfcv->setSpaceCurve(bdcvs[ki]); + crosscvs[ki] = CreatorsUtils::createCrossTangent(*tmp_sfcv); + } + + // Ensure correct direction of cross tangent curves + for (size_t ki=0; ki<crosscvs.size(); ++ki) + { + size_t kj = (ki == crosscvs.size()-1) ? 0 : ki+1; + Point ctan = crosscvs[ki]->point(crosscvs[ki]->endparam()); + double tdel = bdcvs[kj]->endparam() - bdcvs[kj]->startparam(); + Point pos1 = bdcvs[kj]->point(bdcvs[kj]->startparam()); + Point pos2 = bdcvs[kj]->point(bdcvs[kj]->startparam() + 0.1*tdel); + Point vec = pos2 - pos1; + if (ctan*vec < 0.0) + { + shared_ptr<SplineCurve> cross = + dynamic_pointer_cast<SplineCurve,ParamCurve>(crosscvs[ki]); + for (auto it=cross->coefs_begin(); it!=cross->coefs_end(); ++it) + (*it) *= -1.0; + } + } + return true; +} + +void pairOfRegionEdges(RevEngRegion* blendreg, HedgeSurface *hedge, + shared_ptr<ParamCurve>& bdcv1, + shared_ptr<CurveOnSurface>& bdcv2, + RevEngRegion* adjreg, Point& mid, double tol) +{ + int stat = 0; + double eps = 1.0e-9; + shared_ptr<ftEdge> blend_edge(new ftEdge(hedge, bdcv1, + bdcv1->startparam(), + bdcv1->endparam())); + blendreg->addTrimEdge(blend_edge); + + int pdir; + double pval; + if (adjreg->hasBlendEdge() && bdcv2->isConstantCurve(tol, pdir, pval)) + { + shared_ptr<ElementarySurface> adj_elem = + dynamic_pointer_cast<ElementarySurface,ParamSurface>(adjreg->getSurface(0)->surface()); + if (adj_elem.get()) + { + RectDomain adjdom = adj_elem->getParameterBounds(); + double regdom[4]; + adjreg->getDomain(regdom); + // double tmin = regdom[2*(pdir-1)]; + // double tmax = regdom[2*(pdir-1)+1]; + double upar, vpar, dist; + Point close; + adj_elem->closestPoint(mid, upar, vpar, close, dist, eps); + if (pdir == 1) + { + if (upar > pval) + adj_elem->setParameterBounds(adjdom.umin(), adjdom.vmin(), + pval, adjdom.vmax()); + else + adj_elem->setParameterBounds(pval, adjdom.vmin(), + adjdom.umax(), adjdom.vmax()); + } + else + { + if (vpar > pval) + adj_elem->setParameterBounds(adjdom.umin(), adjdom.vmin(), + adjdom.umax(), pval); + else + adj_elem->setParameterBounds(adjdom.umin(), pval, + adjdom.umax(), adjdom.vmax()); + } + // if (fabs(tmax-pval) > fabs(pval-tmin)) + // { + // if (pdir == 1) + // adj_elem->setParameterBounds(pval, adjdom.vmin(), + // adjdom.umax(), adjdom.vmax()); + // else + // adj_elem->setParameterBounds(adjdom.umin(), pval, + // adjdom.umax(), adjdom.vmax()); + // } + // else + // { + // if (pdir == 1) + // adj_elem->setParameterBounds(adjdom.umin(), adjdom.vmin(), + // pval, adjdom.vmax()); + // else + // adj_elem->setParameterBounds(adjdom.umin(), adjdom.vmin(), + // adjdom.umax(), pval); + // } + } + adjreg->adaptEdges(); + } + + HedgeSurface *other_hedge = adjreg->getSurface(0); + shared_ptr<ftEdge> other_edge(new ftEdge(other_hedge, bdcv2, + bdcv2->startparam(), + bdcv2->endparam())); + adjreg->addTrimEdge(other_edge); + other_edge->setReversed(true); + blend_edge->connectTwin(other_edge.get(), stat); +} + +//=========================================================================== +void RevEng::extractOutPoints(vector<RevEngPoint*>& points, shared_ptr<ParamSurface> surf, + vector<int>& cv_ix, + double tol, double angtol, + vector<vector<RevEngPoint*> >& move2adj, + vector<RevEngPoint*>& remain) +//=========================================================================== +{ + double eps = 1.0e-9; + double maxd, avd; + int num_in, num2_in; + vector<double> parvals; + vector<pair<double,double> > dist_ang; + vector<RevEngPoint*> inpt, outpt; + RevEngUtils::distToSurf(points.begin(), points.end(), surf, + tol, maxd, avd, num_in, num2_in, inpt, outpt, + parvals, dist_ang, angtol); + + RectDomain dom = surf->containingDomain(); + for (size_t ki=0; ki<points.size(); ++ki) + { + int bd=-1, bd2=-1; + Vector2D par = Vector2D(parvals[2*ki], parvals[2*ki+1]); + if (dom.isOnBoundary(par, eps, bd, bd2)) + { + if (bd2 >= 0) + { + // Check best fit + } + int move_ix = (bd == 0) ? cv_ix[3] : + ((bd == 1) ? cv_ix[1] : ((bd == 2) ? cv_ix[0] : cv_ix[2])); + move2adj[move_ix].push_back(points[ki]); + } + else + remain.push_back(points[ki]); + } +} + +//=========================================================================== +bool RevEng::suitcaseCorner(vector<RevEngRegion*>& adj_blends, + RevEngEdge* rev_edge) +//=========================================================================== +{ + vector<vector<shared_ptr<ftEdge> > > trim_edgs(adj_blends.size()); + vector<vector<pair<double, double> > > par_lim(adj_blends.size()); + for (size_t ki=0; ki<adj_blends.size(); ++ki) + { + trim_edgs[ki] = adj_blends[ki]->getTrimEdges(); + par_lim[ki].resize(trim_edgs[ki].size()); + for (size_t kj=0; kj<par_lim[ki].size(); ++kj) + par_lim[ki][kj] = std::make_pair(-1.0, -1.0); // Dummy + } + + vector<vector<size_t> > match; + bool found1 = getBlendRegMatches(adj_blends, trim_edgs, par_lim, match); + if (!found1) + return false; + + vector<vector<pair<double, double> > > midp(par_lim.size()); + bool found2 = getTrimEdgeMidpoint(trim_edgs, par_lim, midp); + if (!found2) + return false; + + // Compute boundary curves + vector<shared_ptr<CurveOnSurface> > blend_bd; + vector<RevEngRegion*> adjreg; + bool found3 = computeCornerBoundaryCurves(adj_blends, trim_edgs, par_lim, + midp, match, approx_tol_, + blend_bd, adjreg); + if (!found3) + return false; + + + // Ensure consistent curve sequence and direction + vector<shared_ptr<CurveOnSurface> > blend_bd0(blend_bd.begin(), blend_bd.end()); + RevEngUtils::setLoopSeq(blend_bd); + +#ifdef DEBUG_BLEND + std::ofstream of4("space_bd2.g2"); + for (size_t kr=0; kr<blend_bd.size(); ++kr) + { + shared_ptr<ParamCurve> space = blend_bd[kr]->spaceCurve(); + space->writeStandardHeader(of4); + space->write(of4); + of4 << "400 1 0 4 255 0 0 255" << std::endl; + of4 << "1" << std::endl; + of4 << space->point(space->startparam()) << std::endl; + } +#endif + + // Ensure non-rational spline boundary curves and extract cross parameter curves + double tol1 = 0.5*approx_tol_; + vector<shared_ptr<ParamCurve> > crosscvs; + vector<shared_ptr<ParamCurve> > bdcvs; + bool found4 = getCoonsBoundaryInfo(blend_bd, tol1, bdcvs, crosscvs); + if (!found4) + return false; + +#ifdef DEBUG_BLEND + std::ofstream of4_2("space_bd3.g2"); + for (size_t kr=0; kr<bdcvs.size(); ++kr) + { + bdcvs[kr]->writeStandardHeader(of4_2); + bdcvs[kr]->write(of4_2); + } +#endif + + // Create surface + shared_ptr<SplineSurface> coons; + if (bdcvs.size() == 4) + { + coons = + shared_ptr<SplineSurface>(CoonsPatchGen::createCoonsPatch(bdcvs, + crosscvs, + tol1, + anglim_)); + RevEngUtils::smoothSurf(coons, 2); + } + else + { + MESSAGE("RevEng::suitcaseCorner. Only 4 boundary curves are supported."); + return false; + } + + if (!coons.get()) + return false; + +#ifdef DEBUG_BLEND + std::ofstream of5("coons_patch.g2"); + coons->writeStandardHeader(of5); + coons->write(of5); +#endif + + // Set trimming curves + double eps = 1.0e-9; + CurveLoop cvloop = SurfaceTools::outerBoundarySfLoop(coons, eps); + vector<shared_ptr<ParamCurve> > loopcvs = cvloop.getCurves(); + + // Define match between boundary curves of corner surface and + // adjacent surfaces + vector<int> cv_ix(loopcvs.size()); + for (size_t ki=0; ki<loopcvs.size(); ++ki) + { + Point mid = loopcvs[ki]->point(0.5*(loopcvs[ki]->startparam()+ + loopcvs[ki]->endparam())); + int ix = -1; + double mindist = std::numeric_limits<double>::max(); + for (size_t kj=0; kj<blend_bd0.size(); ++kj) + { + double tpar, dist; + Point close; + blend_bd0[kj]->closestPoint(mid, blend_bd0[kj]->startparam(), + blend_bd0[kj]->endparam(), tpar, + close, dist); + if (dist < mindist) + { + ix = (int)kj; + mindist = dist; + } + } + cv_ix[ki] = ix; + } + + // Move points from blend region as appropriate. First fetch blend points + vector<RevEngRegion*> blend_regs; + rev_edge->getAllBlendRegs(blend_regs); + vector<RevEngPoint*> blend_pts; + for (size_t ki=0; ki<blend_regs.size(); ++ki) + blend_pts.insert(blend_pts.end(), blend_regs[ki]->pointsBegin(), + blend_regs[ki]->pointsEnd()); + + // double angtol = 5.0*anglim_; + // double maxd, avd; + // int num_in, num2_in; + // vector<double> parvals; + // vector<pair<double,double> > dist_ang; + // vector<RevEngPoint*> inpt, outpt; + // RevEngUtils::distToSurf(blend_pts.begin(), blend_pts.end(), coons, + // approx_tol_, maxd, avd, num_in, num2_in, inpt, outpt, + // parvals, dist_ang, angtol); + + double angtol = 5.0*anglim_; + vector<vector<RevEngPoint*> > move2adj(4); + vector<RevEngPoint*> remain; + extractOutPoints(blend_pts, coons, cv_ix, approx_tol_, angtol, + move2adj, remain); + // RectDomain dom = coons->containingDomain(); + // for (size_t ki=0; ki<blend_pts.size(); ++ki) + // { + // int bd=-1, bd2=-1; + // Vector2D par = Vector2D(parvals[2*ki], parvals[2*ki+1]); + // if (dom.isOnBoundary(par, eps, bd, bd2)) + // { + // if (bd2 >= 0) + // { + // // Check best fit + // } + // int move_ix = (bd == 0) ? cv_ix[3] : + // ((bd == 1) ? cv_ix[1] : ((bd == 2) ? cv_ix[0] : cv_ix[2])); + // move2adj[move_ix].push_back(blend_pts[ki]); + // } + // else + // remain.push_back(blend_pts[ki]); + // } + // if (remain.size() == 0 && remain.size() < blend_pts.size()) + // return false; + + bool OK; + for (size_t ki=0; ki<move2adj.size(); ++ki) + if (move2adj[ki].size() > 0) + OK = adjreg[ki]->addPointsToGroup(move2adj[ki], approx_tol_, angtol); + + // Delete current blend regions + vector<HedgeSurface*> prev_sfs; + for (size_t ki=0; ki<blend_regs.size(); ++ki) + { + //blend_regs[ki]->removeFromAdjacent(); + blend_regs[ki]->setRemove(); + } + + // Create blend region + shared_ptr<RevEngRegion> blendreg(new RevEngRegion(classification_type_, + edge_class_type_, + remain)); + blendreg->setRegionAdjacency(); + regions_.push_back(blendreg); + shared_ptr<HedgeSurface> hedge; + shared_ptr<ParamSurface> blend_tmp = coons; + blendreg->setAssociatedSurface(blend_tmp, approx_tol_, angtol, + min_point_region_, hedge); + rev_edge->setBlendRegSurf(blendreg.get()); + blendreg->setBlendEdge(rev_edge); + if (hedge.get()) + surfaces_.push_back(hedge); + + // Add edges to regions + RectDomain dom = coons->containingDomain(); + double umid = 0.5*(dom.umin()+dom.umax()); + double vmid = 0.5*(dom.vmin()+dom.vmax()); + Point mid = coons->ParamSurface::point(umid, vmid); + for (size_t ki=0; ki<loopcvs.size(); ++ki) + { + shared_ptr<CurveOnSurface> other = blend_bd0[cv_ix[ki]]; + RevEngRegion *adj = adjreg[cv_ix[ki]]; + pairOfRegionEdges(blendreg.get(), hedge.get(), loopcvs[ki], other, adj, mid, + tol1); + } + + // Move points from adjacent regions to corner blend region as appropriate + for (size_t ki=0; ki<adjreg.size(); ++ki) + { + blendreg->growInDomain(adjreg[ki], approx_tol_, angtol); + if (adjreg[ki]->numPoints() == 0) + adjreg[ki]->setRemove(); + } + + // Remove obsolete edge information + RevEngRegion* adj[2]; + rev_edge->getAdjacent(adj[0], adj[1]); + size_t kr; + for (int ka=0; ka<2; ++ka) + { + for (kr=0; kr<adj_blends.size(); ++kr) + if (adj_blends[kr] == adj[ka]) + break; + if (kr == adj_blends.size()) + { + rev_edge->eraseAdjacent(adj[ka]); + break; + } + } + rev_edge->eraseCurves(); + + return true; +} + +//=========================================================================== +bool RevEng::createBlendSurface(int ix) +//=========================================================================== +{ + double angtol = 5.0*anglim_; + double diag = bbox_.low().dist(bbox_.high()); + double eps = 1.0e-6; + double blendlim = std::min(0.1*diag, 30.0*mean_edge_len_); //50.0*mean_edge_len_; + double lenlim = 10.0*mean_edge_len_; //blendlim; + + // Adjacent regions + RevEngRegion* adj[2]; + edges_[ix]->getAdjacent(adj[0], adj[1]); + + if ((!adj[0]) || (!adj[1])) + return false; + if ((!adj[0]->hasSurface()) || (!adj[1]->hasSurface())) + return false; // Something wrong + +#ifdef DEBUG_BLEND + std::ofstream of1("adj_groups.g2"); + adj[0]->writeRegionPoints(of1); + adj[1]->writeRegionPoints(of1); +#endif + + if (adj[0]->hasAssociatedBlend() || adj[1]->hasAssociatedBlend()) + return false; + + // Update intersection curve if necessary + bool updated_edge = false; + if (edges_[ix]->getExtendCount() > 0) + { + vector<shared_ptr<RevEngRegion> > added_regions; + vector<vector<RevEngPoint*> > extract_groups; + vector<HedgeSurface*> out_sfs; + updated_edge = edges_[ix]->extendCurve(int_tol_, approx_tol_, anglim_, diag, lenlim, + blendlim, added_regions, extract_groups, out_sfs); + if (extract_groups.size() > 0 || out_sfs.size() > 0) + surfaceExtractOutput(-1, extract_groups, out_sfs); + for (size_t kj=0; kj<added_regions.size(); ++kj) + { + added_regions[kj]->setRegionAdjacency(); + regions_.push_back(added_regions[kj]); + } + + if (updated_edge) + { + for (int ka=ix+1; ka<(int)edges_.size(); ++ka) + { + // Check for overlap (simplified version) + bool embedded = edges_[ix]->contains(edges_[ka].get(), approx_tol_); + if (embedded) + { + bool done = edges_[ix]->integrate(edges_[ka].get()); + if (done) + edges_.erase(edges_.begin()+ka); + } + } + } + } + + if (updated_edge == false && edges_[ix]->getSurfChangeCount() > 0) + updated_edge = edges_[ix]->updateCurve(int_tol_, approx_tol_, diag); + if (!updated_edge) + edges_[ix]->fixMismatchCurves(approx_tol_); // @@@ Should this be done always? + + if (edges_[ix]->getType() == NOT_BLEND) + return false; // Should not create blend surfaces + + // Regions in blend area + vector<RevEngRegion*> blend_regs; + edges_[ix]->getAllBlendRegs(blend_regs); + + // Intersection curve + vector<shared_ptr<CurveOnSurface> > cvs; + edges_[ix]->getCurve(cvs, true); + + vector<Point> der(2); + cvs[0]->point(der, 0.5*(cvs[0]->startparam()+cvs[0]->endparam()), 1); + +#ifdef DEBUG_BLEND + for (size_t ki=0; ki<cvs.size(); ++ki) + { + shared_ptr<ParamCurve> tmp_cv = cvs[ki]->spaceCurve(); + tmp_cv->writeStandardHeader(of1); + tmp_cv->write(of1); + } +#endif + + // Width + double width = edges_[ix]->getDistance(); + + bool out1 = false, out2 = false; + edges_[ix]->getOuterInfo(out1, out2); + + shared_ptr<ParamSurface> surf1 = adj[0]->getSurface(0)->surface(); + shared_ptr<ParamSurface> surf2 = adj[1]->getSurface(0)->surface(); + ClassType classtype1 = surf1->instanceType(); + ClassType classtype2 = surf2->instanceType(); + if (classtype1 != Class_Plane && classtype1 != Class_Cylinder && + classtype1 != Class_Cone) + return false; + if (classtype2 != Class_Plane && classtype2 != Class_Cylinder && + classtype2 != Class_Cone) + return false; + shared_ptr<ElementarySurface> elem1 = + dynamic_pointer_cast<ElementarySurface,ParamSurface>(surf1); + shared_ptr<ElementarySurface> elem2 = + dynamic_pointer_cast<ElementarySurface,ParamSurface>(surf2); + vector<shared_ptr<ElementarySurface> > elem_sfs(2); + elem_sfs[0] = elem1; + elem_sfs[1] = elem2; + if (!(elem1.get() && elem2.get())) + return false; + Point dir1 = elem1->direction(); + Point norm1 = adj[0]->getMeanNormalTriang(); + if (elem1->instanceType() == Class_Plane && dir1*norm1 < 0.0) + dir1 *= -1; + Point dir2 = elem2->direction(); + Point norm2 = adj[1]->getMeanNormalTriang(); + if (elem2->instanceType() == Class_Plane && dir2*norm2 < 0.0) + dir2 *= -1; + + if (classtype1 == Class_Plane && classtype2 == Class_Plane) + { + // Create cylinder + } + else if (classtype1 == Class_Plane || classtype2 == Class_Plane) + { + // Create torus + } + else if ((classtype1 == Class_Cylinder && classtype2 == Class_Cone) || + (classtype2 == Class_Cylinder && classtype1 == Class_Cone)) + { + // Create torus + } + else + return false; // Not supported + + // Collect points from adjacent surfaces + vector<vector<RevEngPoint*> > blend_pts(3); + double tmin = cvs[0]->startparam(); + double tmax = cvs[0]->endparam(); + for (int ka=0; ka<2; ++ka) + adj[ka]->getNearPoints(cvs[0], tmin, tmax, 2*width, angtol, blend_pts[ka]); + + // Collect points from associated blend regions + for (size_t ki=0; ki<blend_regs.size(); ++ki) + blend_pts[2].insert(blend_pts[2].end(), blend_regs[ki]->pointsBegin(), + blend_regs[ki]->pointsEnd()); + +#ifdef DEBUG_BLEND + std::ofstream of2("blend_pts.g2"); + for (size_t ki=0; ki<3; ++ki) + { + if (blend_pts[ki].size() > 0) + { + of2 << "400 1 0 4 0 255 0 255" << std::endl; + of2 << blend_pts[ki].size() << std::endl; + for (size_t kr=0; kr<blend_pts[ki].size(); ++kr) + of2 << blend_pts[ki][kr]->getPoint() << std::endl; + } + } +#endif + + shared_ptr<ElementarySurface> blend_surf; + double ylen = 0.0; + double axis_ang = dir1.angle(dir2); + int ldir = -1; + if ((classtype1 == Class_Plane && classtype2 == Class_Plane) || + ((classtype1 == Class_Plane || classtype2 == Class_Plane) && + fabs(0.5*M_PI - axis_ang) <= angtol)) + { + // Create cylinder + Point lin1, lin2; + Point dir1_2 = dir1, dir2_2 = dir2; + if (classtype1 == Class_Plane) + lin1 = der[1].cross(dir1); + else + { + double clo_u, clo_v, clo_dist; + Point clo; + surf1->closestPoint(der[0], clo_u, clo_v, clo, clo_dist, eps); + surf1->normal(dir1_2, clo_u, clo_v); + lin1 = der[1].cross(dir1_2); + } + + if (classtype2 == Class_Plane) + lin2 = der[1].cross(dir2); + else + { + double clo_u, clo_v, clo_dist; + Point clo; + surf2->closestPoint(der[0], clo_u, clo_v, clo, clo_dist, eps); + surf2->normal(dir2_2, clo_u, clo_v); + lin2 = der[1].cross(dir2_2); + } + + lin1.normalize(); + if (lin1*dir2_2 < 0.0) + lin1 *= -1; + lin2.normalize(); + if (lin2*dir1_2 < 0.0) + lin2 *= -1; + int sgn = (out1 && out2) ? 1 : -1; + blend_surf = createCylinderBlend(blend_pts, width, der[0], + der[1], lin1, lin2, sgn); + double radius = blend_surf->radius(0.0, 0.0); + //double ang = dir1.angle(dir2); + Point centre = blend_surf->location(); + double xlen = der[0].dist(centre); + ylen = sqrt(xlen*xlen - radius*radius); + + ldir = 1; + } + else + { + int sgn = 1; + if ((classtype1 == Class_Plane && dir1*elem1->direction() < 0.0) || + (classtype2 == Class_Plane && dir2*elem2->direction() < 0.0)) + sgn = -1; + + blend_surf = torusBlend(blend_pts, cvs[0], elem1, elem2, width, + out1, out2, sgn); + + double Rrad = blend_surf->radius(0.0, 0.0); + Point centre = blend_surf->location(); + double xlen = der[0].dist(centre); + ylen = fabs(xlen - Rrad); + + ldir = 1; + } + + if (!blend_surf.get()) + { +#ifdef DEBUG_BLEND + std::cout << "No blend_surf" << std::endl; +#endif + return false; + } + +#ifdef DEBUG_BLEND + for (int ka=0; ka<2; ++ka) + { + int num = adj[ka]->numPoints(); + for (int kb=0; kb<num; ++kb) + if (adj[ka]->getPoint(kb)->region() != adj[ka]) + std::cout << "Inconsistent region pointers, pre sortBlendPoints: " << ka << " " << kb << std::endl; + } +#endif + + // Associate blend points with the appropriate surface (region) + // First remove blend points from the adjacent surfaces + vector<vector<RevEngPoint*> > out_pts(2); + for (int ka=0; ka<2; ++ka) + { + adj[ka]->sortBlendPoints(blend_pts[ka], cvs, ylen, true, out_pts[ka]); + blend_pts[2].insert(blend_pts[2].end(), out_pts[ka].begin(), + out_pts[ka].end()); + } +#ifdef DEBUG_BLEND + for (int ka=0; ka<2; ++ka) + { + int num = adj[ka]->numPoints(); + for (int kb=0; kb<num; ++kb) + if (adj[ka]->getPoint(kb)->region() != adj[ka]) + std::cout << "Inconsistent region pointers, post sortBlendPoints1: " << ka << " " << kb << std::endl; + } +#endif + + // Move blend points to the adjacent surfaces if appropriate + vector<vector<RevEngPoint*> > in_pts(2); + adj[0]->sortBlendPoints(blend_pts[2], cvs, ylen, adj[1], + in_pts[0], in_pts[1]); + +#ifdef DEBUG_BLEND + for (int ka=0; ka<2; ++ka) + { + int num = adj[ka]->numPoints(); + for (int kb=0; kb<num; ++kb) + if (adj[ka]->getPoint(kb)->region() != adj[ka]) + std::cout << "Inconsistent region pointers, post sortBlendPoints2: " << ka << " " << kb << std::endl; + } +#endif + + // Update adjacent surfaces with modified collection of points + for (int ka=0; ka<2; ++ka) + { + adj[ka]->updateWithPointsInOut(out_pts[ka], in_pts[ka], approx_tol_, angtol); + } + + // Delete current blend regions + vector<HedgeSurface*> prev_sfs; + for (size_t ki=0; ki<blend_regs.size(); ++ki) + { + blend_regs[ki]->removeFromAdjacent(); + blend_regs[ki]->clearRegionAdjacency(); + int num_sfs = blend_regs[ki]->numSurface(); + for (int ka=0; ka<num_sfs; ++ka) + prev_sfs.push_back(blend_regs[ki]->getSurface(ka)); + } + edges_[ix]->clearBlendRegions(); + if (blend_regs.size() > 0) + { + int dummy_ix = -1; + updateRegionsAndSurfaces(dummy_ix, blend_regs, prev_sfs); + } + + if (blend_pts[2].size() == 0) + { +#ifdef DEBUG_BLEND + std::cout << "No points for blend_surf" << std::endl; +#endif + return false; + } + + // Define blend region + shared_ptr<RevEngRegion> blendreg(new RevEngRegion(classification_type_, + edge_class_type_, + blend_pts[2])); +#ifdef DEBUG_BLEND + std::ofstream of3("updated_blend_pts.g2"); + adj[0]->writeRegionPoints(of3); + adj[1]->writeRegionPoints(of3); + blendreg->writeRegionPoints(of3); +#endif + + blendreg->setRegionAdjacency(); + regions_.push_back(blendreg); + shared_ptr<HedgeSurface> hedge; + shared_ptr<ParamSurface> blend_surf_tmp = blend_surf; + blendreg->setAssociatedSurface(blend_surf_tmp, approx_tol_, angtol, + min_point_region_, hedge); + if (hedge.get()) + surfaces_.push_back(hedge); + + // // Check blend points + // vector<vector<RevEngPoint*> > out_groups; + // blendreg->extractOutPoints(ldir, approx_tol_, angtol, + // 1.1*angtol, out_groups); + // if (out_groups.size() > 0) + // { + // vector<HedgeSurface*> dummy_sfs; + // surfaceExtractOutput(regions_.size()-1, out_groups, dummy_sfs); + // } + + // Update edge with blend region (surface) + edges_[ix]->setBlendRegSurf(blendreg.get()); + blendreg->setBlendEdge(edges_[ix].get()); + for (int ka=0; ka<2; ++ka) + adj[ka]->updateRegionAdjacency(); + blendreg->setRegionAdjacency(); + //edges_[ix]->setAltRadius(radius1); + + for (int ka=0; ka<2; ++ka) + { + vector<vector<RevEngPoint*> > sep_groups; + adj[ka]->splitRegion(sep_groups); + if (sep_groups.size() > 0) + { + size_t kh; + for (kh=0; kh<regions_.size(); ++kh) + if (regions_[kh].get() == adj[ka]) + break; + vector<HedgeSurface*> dummy_sfs; + surfaceExtractOutput((kh<regions_.size()) ? (int)kh : 0, sep_groups, + dummy_sfs); + } + } + + return true; +} + +//=========================================================================== +double +RevEng::computeTorusRadius(vector<vector<RevEngPoint*> >& blend_pts, + shared_ptr<CurveOnSurface>& cv, + const Point& locp, const Point& normal, + shared_ptr<ElementarySurface> rotational, + double width, bool plane_out, bool rot_out) +//=========================================================================== +{ + double alpha = 0; + shared_ptr<Cone> cone = dynamic_pointer_cast<Cone,ElementarySurface>(rotational); + if (cone.get()) + alpha = cone->getConeAngle(); + Point axis = rotational->direction(); + + // Compute minor radius of torus + double lrad = 0.0; + int lnmb = 0; + double beta = 0.5*M_PI + alpha; + //double phi = 0.5*M_PI - alpha; + double fac = 1.0/sin(0.5*beta); + double div = fac - 1.0; + Point loc = rotational->location(); + double rd = (locp-loc)*axis; + Point centr = loc + rd*axis; + for (size_t kj=0; kj<blend_pts.size(); ++kj) + { + for (size_t ki=0; ki<blend_pts[kj].size(); ++ki) + { + Vector3D xyz = blend_pts[kj][ki]->getPoint(); + Point ptpos(xyz[0], xyz[1], xyz[2]); + + // Localize with respect to the guiding curve(s) + double tpar, dist; + Point close; + cv->closestPoint(ptpos, cv->startparam(), cv->endparam(), + tpar, close, dist); + + // Define line in the point between the adjacent surfaces + vector<Point> der(2); + cv->point(der, tpar, 1); + der[1].normalize(); + Point dir1 = der[1].cross(normal); + Point vec1 = der[0] - centr; + if ((dir1*vec1 < 0.0 && (!rot_out)) || (dir1*vec1 > 0.0 && rot_out)) + dir1 *= -1; + Point dir2 = (plane_out) ? normal : -normal; + Point dir3; + if (alpha > 0) + { + Matrix3D mat; + mat.setToRotation(-alpha, der[1][0], der[1][1], der[1][2]); + Vector3D dir2_2(dir2[0], dir2[1], dir2[2]); + Vector3D dir3_2 = mat*dir2_2; + dir3 = Point(dir3_2[0], dir3_2[1], dir3_2[2]); + } + else + dir3 = dir2; + Point dir4 = 0.5*(dir1 + dir3); +#ifdef DEBUG_BLEND + std::ofstream of("midlin.g2"); + of << "410 1 0 4 0 255 0 255" << std::endl; + of << "1" << std::endl; + of << der[0] << " " << der[0]+dir1 << std::endl; + of << "410 1 0 4 255 0 0 255" << std::endl; + of << "1" << std::endl; + of << der[0] << " " << der[0]+dir4 << std::endl; + of << "410 1 0 4 0 0 255 255" << std::endl; + of << "1" << std::endl; + of << der[0] << " " << der[0]+dir2 << std::endl; + +#endif + shared_ptr<Line> line(new Line(der[0], dir4)); + line->setParameterInterval(-2*width, 2*width); + double lpar, ldist; + Point lclose; + line->closestPoint(ptpos, line->startparam(), line->endparam(), + lpar, lclose, ldist); + if (ldist <= approx_tol_) + { + double dd2 = close.dist(lclose); + double xlen = dd2/div; + lrad += xlen; + lnmb++; + } + int stop_break = 1; + } + } + + if (lnmb > 0) + lrad /= (double)lnmb; + + return lrad; +} + +//=========================================================================== +void RevEng::getTorusParameters(shared_ptr<ElementarySurface> planar, + shared_ptr<ElementarySurface> rotational, + double radius, int sgn1, int sgn2, double& Rrad, + Point& centre, Point& normal, Point& Cx) +//=========================================================================== +{ + Point locp = planar->location(); + normal = planar->direction(); + Point loc = rotational->location(); + Point axis = rotational->direction(); + double rd = (locp - loc)*axis; + Point centre0 = loc + rd*axis; + centre = centre0 - sgn1*radius*normal; + Rrad = rotational->radius(0.0, rd); + double alpha = 0.0; + if (rotational->instanceType() == Class_Cone) + alpha = ((Cone*)(rotational.get()))->getConeAngle(); + double phi = 0.5*M_PI - alpha; + double sd = radius/sin(phi); + Cx = rotational->direction2(); + Rrad += (sgn2*sd); +} + +//=========================================================================== +shared_ptr<Torus> +RevEng::torusBlend(vector<vector<RevEngPoint*> >& blend_pts, + vector<shared_ptr<CurveOnSurface> >& cvs, + const Point& locp, const Point& normal, + shared_ptr<ElementarySurface> rotational, + double width, bool plane_out, bool rot_out) +//=========================================================================== +{ + shared_ptr<Torus> torus; + + double alpha = 0; + shared_ptr<Cone> cone = dynamic_pointer_cast<Cone,ElementarySurface>(rotational); + if (cone.get()) + alpha = cone->getConeAngle(); + Point axis = rotational->direction(); + + // Compute minor radius of torus + double lrad = 0.0; + double d2 = 0.0; + int lnmb = 0; + double beta = 0.5*M_PI + alpha; + double phi = 0.5*M_PI - alpha; + double fac = 1.0/sin(0.5*beta); + double div = fac - 1.0; + Point loc = rotational->location(); + double rd = (locp-loc)*axis; + Point centr = loc + rd*axis; + for (size_t kj=0; kj<blend_pts.size(); ++kj) + { + for (size_t ki=0; ki<blend_pts[kj].size(); ++ki) + { + Vector3D xyz = blend_pts[kj][ki]->getPoint(); + Point ptpos(xyz[0], xyz[1], xyz[2]); + + // Localize with respect to the guiding curve(s) + double tpar, dist=std::numeric_limits<double>::max(); + Point close; + int ix = -1; + for (size_t kr=0; kr<cvs.size(); ++kr) + { + double tpar0, dist0; + Point close0; + cvs[kr]->closestPoint(ptpos, cvs[kr]->startparam(), cvs[kr]->endparam(), + tpar0, close0, dist0); + if (dist0 < dist) + { + tpar = tpar0; + dist = dist0; + close = close0; + ix = (int)kr; + } + if (ix < 0) + continue; + + // Define line in the point between the adjacent surfaces + vector<Point> der(2); + cvs[ix]->point(der, tpar, 1); + der[1].normalize(); + Point dir1 = der[1].cross(normal); + Point vec1 = der[0] - centr; + if ((dir1*vec1 < 0.0 && (!rot_out)) || (dir1*vec1 > 0.0 && rot_out)) + dir1 *= -1; + Point dir2 = (plane_out) ? normal : -normal; + Point dir3; + if (alpha > 0) + { + Matrix3D mat; + mat.setToRotation(-alpha, der[1][0], der[1][1], der[1][2]); + Vector3D dir2_2(dir2[0], dir2[1], dir2[2]); + Vector3D dir3_2 = mat*dir2_2; + dir3 = Point(dir3_2[0], dir3_2[1], dir3_2[2]); + } + else + dir3 = dir2; + Point dir4 = 0.5*(dir1 + dir3); +#ifdef DEBUG_BLEND + std::ofstream of("midlin.g2"); + of << "410 1 0 4 0 255 0 255" << std::endl; + of << "1" << std::endl; + of << der[0] << " " << der[0]+dir1 << std::endl; + of << "410 1 0 4 255 0 0 255" << std::endl; + of << "1" << std::endl; + of << der[0] << " " << der[0]+dir4 << std::endl; + of << "410 1 0 4 0 0 255 255" << std::endl; + of << "1" << std::endl; + of << der[0] << " " << der[0]+dir2 << std::endl; + +#endif + shared_ptr<Line> line(new Line(der[0], dir4)); + line->setParameterInterval(-2*width, 2*width); + double lpar, ldist; + Point lclose; + line->closestPoint(ptpos, line->startparam(), line->endparam(), + lpar, lclose, ldist); + if (ldist <= approx_tol_) + { + double dd2 = close.dist(lclose); + double xlen = dd2/div; + lrad += xlen; + d2 += dd2; + lnmb++; + } + int stop_break = 1; + } + } + } + + if (lnmb > 0) + { + lrad /= (double)lnmb; + d2 /= (double)lnmb; + } + + int sgn1 = (plane_out) ? -1 : 1; + int sgn2 = rot_out ? -1 : 1; + Point pos = centr - sgn1*lrad*normal; + double Rrad = rotational->radius(0.0, rd); + double sd = lrad/sin(phi); + Point Cx = rotational->direction2(); + torus = shared_ptr<Torus>(new Torus(Rrad+sgn2*sd, lrad, pos, normal, Cx)); + if (rot_out) + { + RectDomain dom = torus->getParameterBounds(); + try { + torus->setParameterBounds(dom.umin(), dom.vmin()-M_PI, + dom.umax(), dom.vmax()-M_PI); + } + catch (...) + { + } + } + +#ifdef DEBUG_BLEND + std::ofstream of2("tor_blend.g2"); + torus->writeStandardHeader(of2); + torus->write(of2); + RectDomain dom2 = torus->getParameterBounds(); + vector<shared_ptr<ParamCurve> > tmp_cvs = torus->constParamCurves(dom2.vmin(), true); + tmp_cvs[0]->writeStandardHeader(of2); + tmp_cvs[0]->write(of2); + double tf = (sgn2 == 1) ? 0.5 : 1.5; + vector<shared_ptr<ParamCurve> > tmp_cvs2 = + torus->constParamCurves(dom2.vmin()+tf*M_PI, true); + tmp_cvs2[0]->writeStandardHeader(of2); + tmp_cvs2[0]->write(of2); +#endif + return torus; +} + +//=========================================================================== +double +RevEng::computeTorusRadius(vector<vector<RevEngPoint*> >& blend_pts, + shared_ptr<CurveOnSurface>& cv, + shared_ptr<ElementarySurface> elem1, + shared_ptr<ElementarySurface> elem2, + double width, bool out1, bool out2, int sgn, + double& d2) +//=========================================================================== +{ + d2 = 0.0; + double alpha1 = 0.0, alpha2 = 0.0; + shared_ptr<Cone> cone1 = dynamic_pointer_cast<Cone,ElementarySurface>(elem1); + if (cone1.get()) + alpha1 = cone1->getConeAngle(); + shared_ptr<Cone> cone2 = dynamic_pointer_cast<Cone,ElementarySurface>(elem2); + if (cone2.get()) + alpha2 = cone2->getConeAngle(); + if (cone1.get() && cone2.get()) + return 0.0; // Two cones are not handled + double alpha = fabs(alpha1) + fabs(alpha2); + shared_ptr<Plane> plane; + if (elem1->instanceType() == Class_Plane) + plane = dynamic_pointer_cast<Plane,ElementarySurface>(elem1); + else if (elem2->instanceType() == Class_Plane) + plane = dynamic_pointer_cast<Plane,ElementarySurface>(elem2); + int state = (plane.get()) ? 1 : 2; + shared_ptr<ElementarySurface> rotational; + if (elem1->instanceType() == Class_Plane) + rotational = elem2; + else if (elem2->instanceType() == Class_Plane) + rotational = elem1; + else if (cone1.get()) + rotational = elem2; // elem2 is expected to be a cylinder + else if (cone2.get()) + rotational = elem1; + Point axis = rotational->direction(); + Point normal = (plane.get()) ? plane->direction() : axis; + if (state == 1) + normal *= sgn; + if ((state == 1 && elem2->instanceType() == Class_Plane) || + (state == 2 && elem2->instanceType() == Class_Cylinder)) + std::swap(out1,out2); // Call by value means this swap stays local + + // Compute minor radius of torus + double lrad = 0.0; + int lnmb = 0; + double beta = (plane.get()) ? 0.5*M_PI + alpha : M_PI-fabs(alpha); + //double phi = beta - 2.0*alpha; + double fac = 1.0/sin(0.5*beta); + double div = fac - 1.0; + Point loc = rotational->location(); + Point locp = (plane.get()) ? plane->location() : + cv->ParamCurve::point(0.5*(cv->startparam()+cv->endparam()));; + double rd = (locp-loc)*axis; + Point centr = loc + rd*axis; + for (size_t kj=0; kj<blend_pts.size(); ++kj) + { + for (size_t ki=0; ki<blend_pts[kj].size(); ++ki) + { + Vector3D xyz = blend_pts[kj][ki]->getPoint(); + Point ptpos(xyz[0], xyz[1], xyz[2]); + + // Localize with respect to the guiding curve(s) + double tpar, dist; + Point close; + cv->closestPoint(ptpos, cv->startparam(), cv->endparam(), + tpar, close, dist); + + // Define line in the point between the adjacent surfaces + vector<Point> der(2); + cv->point(der, tpar, 1); + der[1].normalize(); + Point dir1 = der[1].cross(normal); + Point vec1 = der[0] - centr; + if ((dir1*vec1 < 0.0 && (!out2)) || (dir1*vec1 > 0.0 && out2)) + dir1 *= -1; + Point dir2 = (out1) ? normal : -normal; + Point dir3; + if (alpha > 0) + { + Matrix3D mat; + if (state == 1) + mat.setToRotation(-alpha, der[1][0], der[1][1], der[1][2]); + else + mat.setToRotation(0.5*beta, der[1][0], der[1][1], der[1][2]); + Vector3D dir2_2(dir2[0], dir2[1], dir2[2]); + Vector3D dir3_2 = mat*dir2_2; + dir3 = Point(dir3_2[0], dir3_2[1], dir3_2[2]); + } + else + dir3 = dir2; + Point dir4 = (state == 1 )? 0.5*(dir1 + dir3) : dir3; + if (state == 2 && (!out2)) + dir4 *= -1; +#ifdef DEBUG_BLEND + std::ofstream of("midlin.g2"); + of << "410 1 0 4 0 255 0 255" << std::endl; + of << "1" << std::endl; + of << der[0] << " " << der[0]+dir1 << std::endl; + of << "410 1 0 4 255 0 0 255" << std::endl; + of << "1" << std::endl; + of << der[0] << " " << der[0]+dir4 << std::endl; + of << "410 1 0 4 0 0 255 255" << std::endl; + of << "1" << std::endl; + of << der[0] << " " << der[0]+dir2 << std::endl; + of << "410 1 0 4 100 100 55 255" << std::endl; + of << "1" << std::endl; + of << der[0] << " " << der[0]+dir3 << std::endl; + +#endif + shared_ptr<Line> line(new Line(der[0], dir4)); + line->setParameterInterval(-2*width, 2*width); + double lpar, ldist; + Point lclose; + line->closestPoint(ptpos, line->startparam(), line->endparam(), + lpar, lclose, ldist); + if (ldist <= approx_tol_) + { + double dd2 = close.dist(lclose); + double xlen = dd2/div; + lrad += xlen; + d2 += dd2; + lnmb++; + } + int stop_break = 1; + } + } + + + if (lnmb > 0) + { + lrad /= (double)lnmb; + d2 /= (double)lnmb; + } + + return lrad; +} + +//=========================================================================== +bool +RevEng::getTorusParameters(shared_ptr<ElementarySurface> elem1, + shared_ptr<ElementarySurface> elem2, Point pos, + double radius, double d2, bool out1, bool out2, int sgn, + double& Rrad, Point& centre, Point& normal, Point& Cx, + bool check_common) +//=========================================================================== +{ + double alpha1 = 0.0, alpha2 = 0.0; + shared_ptr<Cone> cone1 = dynamic_pointer_cast<Cone,ElementarySurface>(elem1); + if (cone1.get()) + alpha1 = cone1->getConeAngle(); + shared_ptr<Cone> cone2 = dynamic_pointer_cast<Cone,ElementarySurface>(elem2); + if (cone2.get()) + alpha2 = cone2->getConeAngle(); + if (cone1.get() && cone2.get()) + return false; // Two cones are not handled + double alpha = fabs(alpha1) + fabs(alpha2); + shared_ptr<Plane> plane; + if (elem1->instanceType() == Class_Plane) + plane = dynamic_pointer_cast<Plane,ElementarySurface>(elem1); + else if (elem2->instanceType() == Class_Plane) + plane = dynamic_pointer_cast<Plane,ElementarySurface>(elem2); + int state = (plane.get()) ? 1 : 2; + shared_ptr<ElementarySurface> rotational; + if (elem1->instanceType() == Class_Plane) + rotational = elem2; + else if (elem2->instanceType() == Class_Plane) + rotational = elem1; + else if (cone1.get()) + rotational = elem2; // elem2 is expected to be a cylinder + else if (cone2.get()) + rotational = elem1; + Point axis = rotational->direction(); + normal = (plane.get()) ? plane->direction() : axis; + if (state == 1) + normal *= sgn; + Point loc = rotational->location(); + if ((state == 1 && elem2->instanceType() == Class_Plane) || + (state == 2 && elem2->instanceType() == Class_Cylinder)) + std::swap(out1,out2); // Call by value means this swap stays local + + double rd = (pos-loc)*axis; + Point centr = loc + rd*axis; + double beta = (plane.get()) ? 0.5*M_PI + alpha : M_PI-fabs(alpha); + double phi = beta - 2.0*alpha; + double phi2 = 0.5*(M_PI - beta); + int sgn1 = (out1) ? -1 : 1; + int sgn2 = out2 ? -1 : 1; + if (state == 2) + { + sgn2 *= -1; + } + double hh = (state == 1) ? radius : sgn2*(radius + d2)*sin(phi2); + centre = centr - sgn1*hh*normal; + Rrad = rotational->radius(0.0, rd); + double sd = (state == 1) ? radius/sin(phi) : (radius + d2)*cos(phi2); + Cx = rotational->direction2(); + Rrad += (sgn2*sd); + if (radius > Rrad && check_common) + return false; + +#ifdef DEBUG_BLEND + shared_ptr<Torus> torus(new Torus(Rrad, radius, centre, normal, Cx)); + // if (sgn2 < 0) + // { + // RectDomain dom = torus->getParameterBounds(); + // torus->setParameterBounds(dom.umin(), dom.vmin()-M_PI, + // dom.umax(), dom.vmax()-M_PI); + // } + std::ofstream of2("tor_blend.g2"); + torus->writeStandardHeader(of2); + torus->write(of2); + RectDomain dom2 = torus->getParameterBounds(); + vector<shared_ptr<ParamCurve> > tmp_cvs = torus->constParamCurves(dom2.vmin(), true); + tmp_cvs[0]->writeStandardHeader(of2); + tmp_cvs[0]->write(of2); + double tf = (sgn2 == 1) ? 0.5 : 1.5; + vector<shared_ptr<ParamCurve> > tmp_cvs2 = + torus->constParamCurves(dom2.vmin()+tf*M_PI, true); + tmp_cvs2[0]->writeStandardHeader(of2); + tmp_cvs2[0]->write(of2); +#endif + return true; +} + +//=========================================================================== +shared_ptr<Torus> +RevEng::torusBlend(vector<vector<RevEngPoint*> >& blend_pts, + shared_ptr<CurveOnSurface>& cv, + shared_ptr<ElementarySurface> elem1, + shared_ptr<ElementarySurface> elem2, + double width, bool out1, bool out2, int sgn) +//=========================================================================== +{ + shared_ptr<Torus> torus; + + double alpha1 = 0.0, alpha2 = 0.0; + shared_ptr<Cone> cone1 = dynamic_pointer_cast<Cone,ElementarySurface>(elem1); + if (cone1.get()) + alpha1 = cone1->getConeAngle(); + shared_ptr<Cone> cone2 = dynamic_pointer_cast<Cone,ElementarySurface>(elem2); + if (cone2.get()) + alpha2 = cone2->getConeAngle(); + if (cone1.get() && cone2.get()) + return torus; // Two cones are not handled + double alpha = fabs(alpha1) + fabs(alpha2); + shared_ptr<Plane> plane; + if (elem1->instanceType() == Class_Plane) + plane = dynamic_pointer_cast<Plane,ElementarySurface>(elem1); + else if (elem2->instanceType() == Class_Plane) + plane = dynamic_pointer_cast<Plane,ElementarySurface>(elem2); + int state = (plane.get()) ? 1 : 2; + shared_ptr<ElementarySurface> rotational; + if (elem1->instanceType() == Class_Plane) + rotational = elem2; + else if (elem2->instanceType() == Class_Plane) + rotational = elem1; + else if (cone1.get()) + rotational = elem2; // elem2 is expected to be a cylinder + else if (cone2.get()) + rotational = elem1; + Point axis = rotational->direction(); + Point normal = (plane.get()) ? plane->direction() : axis; + if (state == 1) + normal *= sgn; + if ((state == 1 && elem2->instanceType() == Class_Plane) || + (state == 2 && elem2->instanceType() == Class_Cylinder)) + std::swap(out1,out2); // Call by value means this swap stays local + + // Compute minor radius of torus + double lrad = 0.0; + double d2 = 0.0; + int lnmb = 0; + double beta = (plane.get()) ? 0.5*M_PI + alpha : M_PI-fabs(alpha); + double phi = beta - 2.0*alpha; + double fac = 1.0/sin(0.5*beta); + double div = fac - 1.0; + Point loc = rotational->location(); + Point locp = (plane.get()) ? plane->location() : + cv->ParamCurve::point(0.5*(cv->startparam()+cv->endparam()));; + double rd = (locp-loc)*axis; + Point centr = loc + rd*axis; + for (size_t kj=0; kj<blend_pts.size(); ++kj) + { + for (size_t ki=0; ki<blend_pts[kj].size(); ++ki) + { + Vector3D xyz = blend_pts[kj][ki]->getPoint(); + Point ptpos(xyz[0], xyz[1], xyz[2]); + + // Localize with respect to the guiding curve(s) + double tpar, dist; + Point close; + cv->closestPoint(ptpos, cv->startparam(), cv->endparam(), + tpar, close, dist); + + // Define line in the point between the adjacent surfaces + vector<Point> der(2); + cv->point(der, tpar, 1); + der[1].normalize(); + Point dir1 = der[1].cross(normal); + Point vec1 = der[0] - centr; + if ((dir1*vec1 < 0.0 && (!out2)) || (dir1*vec1 > 0.0 && out2)) + dir1 *= -1; + Point dir2 = (out1) ? normal : -normal; + Point dir3; + if (alpha > 0) + { + Matrix3D mat; + if (state == 1) + mat.setToRotation(-alpha, der[1][0], der[1][1], der[1][2]); + else + mat.setToRotation(0.5*beta, der[1][0], der[1][1], der[1][2]); + Vector3D dir2_2(dir2[0], dir2[1], dir2[2]); + Vector3D dir3_2 = mat*dir2_2; + dir3 = Point(dir3_2[0], dir3_2[1], dir3_2[2]); + } + else + dir3 = dir2; + Point dir4 = (state == 1 )? 0.5*(dir1 + dir3) : dir3; + if (state == 2 && (!out2)) + dir4 *= -1; +#ifdef DEBUG_BLEND + std::ofstream of("midlin.g2"); + of << "410 1 0 4 0 255 0 255" << std::endl; + of << "1" << std::endl; + of << der[0] << " " << der[0]+dir1 << std::endl; + of << "410 1 0 4 255 0 0 255" << std::endl; + of << "1" << std::endl; + of << der[0] << " " << der[0]+dir4 << std::endl; + of << "410 1 0 4 0 0 255 255" << std::endl; + of << "1" << std::endl; + of << der[0] << " " << der[0]+dir2 << std::endl; + of << "410 1 0 4 100 100 55 255" << std::endl; + of << "1" << std::endl; + of << der[0] << " " << der[0]+dir3 << std::endl; + +#endif + shared_ptr<Line> line(new Line(der[0], dir4)); + line->setParameterInterval(-2*width, 2*width); + double lpar, ldist; + Point lclose; + line->closestPoint(ptpos, line->startparam(), line->endparam(), + lpar, lclose, ldist); + if (ldist <= approx_tol_) + { + double dd2 = close.dist(lclose); + double xlen = dd2/div; + lrad += xlen; + d2 += dd2; + lnmb++; + } + int stop_break = 1; + } + } + + + if (lnmb > 0) + { + lrad /= (double)lnmb; + d2 /= (double)lnmb; + } + + int sgn1 = (out1) ? -1 : 1; + int sgn2 = out2 ? -1 : 1; + if (state == 2) + { + sgn2 *= -1; + } + double phi2 = 0.5*(M_PI - beta); + double hh = (state == 1) ? lrad : sgn2*(lrad + d2)*sin(phi2); + Point pos = centr - sgn1*hh*normal; + double Rrad = rotational->radius(0.0, rd); + double sd = (state == 1) ? lrad/sin(phi) : (lrad + d2)*cos(phi2); + Point Cx = rotational->direction2(); + torus = shared_ptr<Torus>(new Torus(Rrad+sgn2*sd, lrad, pos, normal, Cx)); + if (sgn2 > 0) + { + RectDomain dom = torus->getParameterBounds(); + try { + torus->setParameterBounds(dom.umin(), dom.vmin()-M_PI, + dom.umax(), dom.vmax()-M_PI); + } + catch (...) + { + } + } + +#ifdef DEBUG_BLEND + std::ofstream of2("tor_blend.g2"); + torus->writeStandardHeader(of2); + torus->write(of2); + RectDomain dom2 = torus->getParameterBounds(); + vector<shared_ptr<ParamCurve> > tmp_cvs = torus->constParamCurves(dom2.vmin(), true); + tmp_cvs[0]->writeStandardHeader(of2); + tmp_cvs[0]->write(of2); + double tf = (sgn2 == 1) ? 0.5 : 1.5; + vector<shared_ptr<ParamCurve> > tmp_cvs2 = + torus->constParamCurves(dom2.vmin()+tf*M_PI, true); + tmp_cvs2[0]->writeStandardHeader(of2); + tmp_cvs2[0]->write(of2); +#endif + return torus; +} + +//=========================================================================== +double +RevEng::computeCylinderRadius(vector<vector<RevEngPoint*> > blend_pts, + double width, const Point& pos, const Point& axis, + const Point& dir1, const Point& dir2) +//=========================================================================== +{ + double eps = 1.0e-6; + double upar2, vpar2, dist2; + Point close, surfnorm, close2; + double alpha = dir1.angle(dir2); + Point linedir = width*dir1 + width*dir2; + Point planenorm = linedir.cross(axis); + planenorm.normalize(); + shared_ptr<Plane> plane(new Plane(pos, planenorm, linedir)); + double lrad = 0.0; + int lnmb = 0; + double fac = 1.0/sin(0.5*alpha); + double div = fac - 1.0; + for (size_t kj=0; kj<blend_pts.size(); ++kj) + { + for (size_t ki=0; ki<blend_pts[kj].size(); ++ki) + { + Vector3D xyz = blend_pts[kj][ki]->getPoint(); + Point ptpos(xyz[0], xyz[1], xyz[2]); + + plane->closestPoint(ptpos, upar2, vpar2, close2, dist2, eps); + if (dist2 <= approx_tol_) + { + Point pos2 = plane->ParamSurface::point(0.0, vpar2); + double dd2 = pos2.dist(close2); + double xlen = dd2/div; + lrad += xlen; + lnmb++; + } + } + } + if (lnmb > 0) + lrad /= (double)lnmb; + return lrad; +} + + +//=========================================================================== +shared_ptr<Cylinder> +RevEng::createCylinderBlend(vector<vector<RevEngPoint*> > blend_pts, + double rad1, const Point& pos, const Point& axis, + const Point& dir1, const Point& dir2, int sgn) +//=========================================================================== +{ + double eps = 1.0e-6; + double upar2, vpar2, dist2; + Point close, surfnorm, close2; + double alpha = dir1.angle(dir2); + Point linedir = rad1*dir1 + rad1*dir2; + Point planenorm = linedir.cross(axis); + planenorm.normalize(); + shared_ptr<Plane> plane(new Plane(pos, planenorm, linedir)); + double lrad = 0.0; + int lnmb = 0; + double fac = 1/sin(0.5*alpha); + double div = fac - 1.0; + for (size_t kj=0; kj<blend_pts.size(); ++kj) + { + for (size_t ki=0; ki<blend_pts[kj].size(); ++ki) + { + Vector3D xyz = blend_pts[kj][ki]->getPoint(); + Point ptpos(xyz[0], xyz[1], xyz[2]); + + plane->closestPoint(ptpos, upar2, vpar2, close2, dist2, eps); + if (dist2 <= approx_tol_) + { + Point pos2 = plane->ParamSurface::point(0.0, vpar2); + double dd2 = pos2.dist(close2); + double xlen = dd2/div; + lrad += xlen; + lnmb++; + } + } + } + if (lnmb > 0) + lrad /= (double)lnmb; + + Point Cx = sgn*(dir1 + dir2); + Point Cy = axis.cross(Cx); + // Point pos2; + // double rad2; + Point low = bbox_.low(); + Point high = bbox_.high(); + + Point vec = dir1 + dir2; + vec.normalize(); + Point pos3 = pos + sgn*fac*lrad*vec; + shared_ptr<Cylinder> cyl(new Cylinder(lrad, pos3, axis, Cx)); + double diag = low.dist(high); + cyl->setParamBoundsV(-0.5*diag,0.5*diag); + +#ifdef DEBUG_BLEND + std::ofstream of("blend_cyl2.g2"); + cyl->writeStandardHeader(of); + cyl->write(of); +#endif + + + return cyl; +} + + + +//=========================================================================== +void RevEng::surfaceExtractOutput(int idx, + vector<vector<RevEngPoint*> > out_groups, + vector<HedgeSurface*> prev_surfs) +//=========================================================================== +{ + for (size_t kr=0; kr<out_groups.size(); ++kr) + { + for (size_t kh=0; kh<out_groups[kr].size(); ++kh) + out_groups[kr][kh]->unsetRegion(); + } + + int classtype = (idx >= 0) ? regions_[idx]->getClassification() : + CLASSIFICATION_UNDEF; + for (size_t kr=0; kr<out_groups.size(); ++kr) + { + shared_ptr<RevEngRegion> reg(new RevEngRegion(classtype, + edge_class_type_, + out_groups[kr])); + if (idx >= 0) + reg->setPreviousReg(regions_[idx].get()); + reg->setRegionAdjacency(); +#ifdef DEBUG_CHECK + bool connect = reg->isConnected(); + connect = reg->isConnected(); + if (!connect) + { + std::cout << "surfaceExtractOutput, disconnected region " << idx << std::endl; + } +#endif + bool integrate = reg->integrateInAdjacent(mean_edge_len_, + min_next_, max_next_, + approx_tol_, 0.5, + max_nmb_outlier_, + (idx >= 0) ? regions_[idx].get() : 0); + if (!integrate) + regions_.push_back(reg); + } + for (size_t kr=0; kr<prev_surfs.size(); ++kr) + { + size_t kj; + for (kj=0; kj<surfaces_.size(); ++kj) + if (surfaces_[kj].get() == prev_surfs[kr]) + break; + if (kj < surfaces_.size()) + surfaces_.erase(surfaces_.begin()+kj); + } +} + +//=========================================================================== +bool RevEng::segmentByPlaneGrow(int ix, int min_point_in, double angtol) +//=========================================================================== +{ +#ifdef DEBUG + std::ofstream ofreg("segment_reg.g2"); + regions_[ix]->writeRegionInfo(ofreg); +#endif + + vector<shared_ptr<HedgeSurface> > plane_sfs; + vector<HedgeSurface*> prev_surfs; + vector<vector<RevEngPoint*> > out_groups; + regions_[ix]->segmentByPlaneGrow(mainaxis_, approx_tol_, angtol, min_point_in, + plane_sfs, prev_surfs, out_groups); +#ifdef DEBUG + for (size_t ki=0; ki<plane_sfs.size(); ++ki) + { + plane_sfs[ki]->surface()->writeStandardHeader(ofreg); + plane_sfs[ki]->surface()->write(ofreg); + } +#endif + + if (out_groups.size() > 0 || prev_surfs.size() > 0) + surfaceExtractOutput(ix, out_groups, prev_surfs); + if (plane_sfs.size() > 0) + surfaces_.insert(surfaces_.end(), plane_sfs.begin(), plane_sfs.end()); + + bool segmented = (out_groups.size() > 0); + return segmented; +} + +//=========================================================================== +bool RevEng::segmentByAxis(int ix, int min_point_in) +//=========================================================================== +{ + double angtol = 5.0*anglim_; + vector<shared_ptr<HedgeSurface> > hedgesfs; + vector<shared_ptr<RevEngRegion> > added_reg; + vector<vector<RevEngPoint*> > separate_groups; + vector<RevEngPoint*> single_points; + bool segmented = regions_[ix]->extractCylByAxis(mainaxis_, min_point_in, + min_point_region_, + approx_tol_, angtol, + prefer_elementary_, + hedgesfs, added_reg, + separate_groups, + single_points); + if (segmented && single_points.size() > 0) + single_points_.insert(single_points_.end(), single_points.begin(), + single_points.end()); +#ifdef DEBUG + if (segmented) + { + std::ofstream of("seg_by_axis.g2"); + int num = regions_[ix]->numPoints(); + of << "400 1 0 4 255 0 0 255" << std::endl; + of << num << std::endl; + for (int ka=0; ka<num; ++ka) + of << regions_[ix]->getPoint(ka)->getPoint() << std::endl; + + for (size_t ki=0; ki<separate_groups.size(); ++ki) + { + of << "400 1 0 4 0 255 0 255" << std::endl; + of << separate_groups[ki].size() << std::endl; + for (int ka=0; ka<(int)separate_groups[ki].size(); ++ka) + of << separate_groups[ki][ka]->getPoint() << std::endl; + } + } +#endif + + if (separate_groups.size() > 0) + { + vector<HedgeSurface*> prev_surfs; + surfaceExtractOutput(ix, separate_groups, prev_surfs); + } + + if (added_reg.size() > 0) + regions_.insert(regions_.end(), added_reg.begin(), added_reg.end()); + if (hedgesfs.size() > 0) + surfaces_.insert(surfaces_.end(), hedgesfs.begin(), hedgesfs.end()); + + return segmented; +} + +//=========================================================================== +bool RevEng::segmentByContext(int ix, int min_point_in, double angtol, bool first) +//=========================================================================== +{ +#ifdef DEBUG_DIV + vector<RevEngPoint*> branchpt = regions_[ix]->extractBranchPoints(); + if (branchpt.size() > 0) + { + std::ofstream ofb("branch_pts_seg.g2"); + ofb << "400 1 0 4 0 0 0 255" << std::endl; + ofb << branchpt.size() << std::endl; + for (size_t ki=0; ki<branchpt.size(); ++ki) + ofb << branchpt[ki]->getPoint() << std::endl; + } + +#endif + + vector<vector<RevEngPoint*> > separate_groups; + vector<RevEngRegion*> adj_planar = regions_[ix]->fetchAdjacentPlanar(); + vector<shared_ptr<HedgeSurface> > hedgesfs; + vector<shared_ptr<RevEngRegion> > added_reg; + vector<HedgeSurface*> prevsfs; + bool segmented = false; + if (adj_planar.size() > 1) + { + segmented = regions_[ix]->segmentByPlaneAxis(mainaxis_, min_point_in, + min_point_region_, + approx_tol_, angtol, + prefer_elementary_, + adj_planar, hedgesfs, + added_reg, + prevsfs, separate_groups); + } + + if (!segmented) + { + // Extend with cylindrical + vector<RevEngRegion*> adj_cyl = regions_[ix]->fetchAdjacentCylindrical(); + if (adj_cyl.size() > 0) + adj_planar.insert(adj_planar.end(), adj_cyl.begin(), adj_cyl.end()); + if (adj_planar.size() > 0) + segmented = + regions_[ix]->segmentByAdjSfContext(mainaxis_, min_point_in, + min_point_region_, + approx_tol_, angtol, + adj_planar, separate_groups); + } + + if (!segmented) + { + // Search for context direction + double angtol2 = 2.0*angtol; + + Point direction = regions_[ix]->directionFromAdjacent(angtol); + vector<vector<RevEngPoint*> > separate_groups2; + if (direction.dimension() == 3) + segmented = regions_[ix]->segmentByDirectionContext(min_point_in, approx_tol_, + direction, angtol2, + separate_groups2); + if (separate_groups2.size() > 0) + separate_groups.insert(separate_groups.end(), separate_groups2.begin(), + separate_groups2.end()); + if (segmented && (!regions_[ix]->hasSurface())) + { + double angtol = -1.0; + int pass = 1; + bool found = recognizeOneSurface(ix, min_point_in, angtol, pass); + int stop_break = 1; + } + } + +#ifdef DEBUG + if (segmented) + { + std::ofstream of("seg_by_context.g2"); + int num = regions_[ix]->numPoints(); + of << "400 1 0 4 255 0 0 255" << std::endl; + of << num << std::endl; + for (int ka=0; ka<num; ++ka) + of << regions_[ix]->getPoint(ka)->getPoint() << std::endl; + + for (size_t ki=0; ki<separate_groups.size(); ++ki) + { + of << "400 1 0 4 0 255 0 255" << std::endl; + of << separate_groups[ki].size() << std::endl; + for (int ka=0; ka<(int)separate_groups[ki].size(); ++ka) + of << separate_groups[ki][ka]->getPoint() << std::endl; + } + } +#endif + + if (separate_groups.size() > 0) + { + vector<HedgeSurface*> prev_surfs; + surfaceExtractOutput(ix, separate_groups, prev_surfs); + } + + if (added_reg.size() > 0) + regions_.insert(regions_.end(), added_reg.begin(), added_reg.end()); + if (hedgesfs.size() > 0) + surfaces_.insert(surfaces_.end(), hedgesfs.begin(), hedgesfs.end()); + + return segmented; +} + +//=========================================================================== +void RevEng::growSurface(int& ix, int pass) +//=========================================================================== +{ + vector<RevEngRegion*> grown_regions; + int min_nmb = 5*min_point_region_; // Should be set from distribution of how many + // points the regions have + double angtol = 5.0*anglim_; + vector<HedgeSurface*> adj_surfs; + vector<RevEngEdge*> adj_edgs; + regions_[ix]->growWithSurf(mainaxis_, min_point_region_, + approx_tol_, angtol, grown_regions, + adj_surfs, adj_edgs, (pass>1)); + updateRegionsAndSurfaces(ix, grown_regions, adj_surfs); + for (size_t ki=0; ki<adj_edgs.size(); ++ki) + { + size_t kj; + for (kj=0; kj<edges_.size(); ++kj) + if (edges_[kj].get() == adj_edgs[ki]) + break; + if (kj < edges_.size()) + edges_.erase(edges_.begin()+kj); + } +} + +//=========================================================================== +void RevEng::growBlendSurface(int& ix) +//=========================================================================== +{ + // Collect associated blend surfaces + RevEngEdge *edge = regions_[ix]->getBlendEdge(); + if (!edge) + return; + +#ifdef DEBUG_BLEND + std::ofstream of("blend_grow.g2"); + regions_[ix]->writeRegionPoints(of); +#endif + + vector<RevEngRegion*> next_blend; + RevEngRegion *adj[2]; + edge->getAdjacent(adj[0], adj[1]); + for (int ka=0; ka<2; ++ka) + { + if (!adj[ka]) + continue; + vector<RevEngEdge*> rev_edgs = adj[ka]->getAllRevEdges(); + for (size_t ki=0; ki<rev_edgs.size(); ++ki) + { + RevEngRegion *blendreg = rev_edgs[ki]->getBlendRegSurf(); + if (blendreg) + { + if (blendreg == regions_[ix].get()) + continue; + size_t kj=0; + for (kj=0; kj<next_blend.size(); ++kj) + if (next_blend[kj] == blendreg) + break; + if (kj < next_blend.size()) + continue; + next_blend.push_back(blendreg); + } + } + } + +#ifdef DEBUG_BLEND + for (size_t kr=0; kr<next_blend.size(); ++kr) + next_blend[kr]->writeRegionPoints(of); +#endif + + vector<RevEngRegion*> grown_regions; + double angtol = 5.0*anglim_; + vector<HedgeSurface*> adj_surfs; + vector<vector<RevEngPoint*> > added_regs; + regions_[ix]->growBlendSurf(next_blend, approx_tol_, angtol, + grown_regions, added_regs); + + updateRegionsAndSurfaces(ix, grown_regions, adj_surfs); + if (added_regs.size() > 0) + { + vector<HedgeSurface*> prev_surfs; + surfaceExtractOutput(ix, added_regs, prev_surfs); + } +} + +//=========================================================================== +void RevEng::growMasterSurface(int& ix) +//=========================================================================== +{ + +#ifdef DEBUG_BLEND + std::ofstream of("master_grow.g2"); + regions_[ix]->writeRegionPoints(of); +#endif + + vector<RevEngRegion*> grown_regions; + double angtol = 5.0*anglim_; + vector<HedgeSurface*> adj_surfs; + int small_lim = min_point_region_/20; + regions_[ix]->joinToCurrent(approx_tol_, angtol, small_lim, + grown_regions); + + updateRegionsAndSurfaces(ix, grown_regions, adj_surfs); +} + + +//=========================================================================== +void RevEng::updateRegionsAndSurfaces(int& ix, vector<RevEngRegion*>& grown_regions, + vector<HedgeSurface*>& adj_surfs) +//=========================================================================== +{ + if (grown_regions.size() > 0) + { + for (size_t kr=0; kr<grown_regions.size(); ++kr) + { +// #ifdef DEBUG_CHECK +// bool connect = grown_regions[kr]->isConnected(); +// connect = grown_regions[kr]->isConnected(); +// if (!connect) +// std::cout << "updateRegionsAndSurfaces, disconnected region " << ix << kr << std::endl; +// #endif + size_t kj; + for (kj=0; kj<regions_.size(); ) + { + if ((int)kj == ix) + { + ++kj; + continue; + } + + if (grown_regions[kr] == regions_[kj].get()) + { + regions_.erase(regions_.begin()+kj); + if ((int)kj < ix) + --ix; + } + else + ++kj; + } + } + for (size_t kr=0; kr<adj_surfs.size(); ++kr) + { + size_t kj; + for (kj=0; kj<surfaces_.size(); ++kj) + if (surfaces_[kj].get() == adj_surfs[kr]) + break; + if (kj < surfaces_.size()) + surfaces_.erase(surfaces_.begin()+kj); + } + } + + for (size_t kj=0; kj<regions_.size(); ++kj) + regions_[kj]->setVisited(false); + +// #ifdef DEBUG_DIV +// std::ofstream ofpts("sfpoints2.g2"); +// std::ofstream ofpar("sfparpoints2.txt"); +// int numpt = regions_[ix]->numPoints(); +// ofpts << "400 1 0 0" << std::endl; +// ofpts << numpt << std::endl; +// for (int ka=0; ka<numpt; ++ka) +// { +// RevEngPoint *pt = regions_[ix]->getPoint(ka); +// ofpar << pt->getPar() << " " << pt->getPoint() << std::endl; +// ofpts << pt->getPoint() << std::endl; +// } +// #endif + int stop_break = 1; + +} + + +//=========================================================================== +void RevEng::smallRegionSurfaces() +//=========================================================================== +{ + // Update adjacency between regions + for (size_t ki=0; ki<regions_.size(); ++ki) + { + regions_[ki]->clearRegionAdjacency(); + } + for (size_t ki=0; ki<regions_.size(); ++ki) + { + regions_[ki]->setRegionAdjacency(); + } + + // Add possible missing edges + recognizeEdges(); + + // Update adjacency between regions + for (size_t ki=0; ki<regions_.size(); ++ki) + { + regions_[ki]->clearRegionAdjacency(); + } + for (size_t ki=0; ki<regions_.size(); ++ki) + { + regions_[ki]->setRegionAdjacency(); + } + + +#ifdef DEBUG + std::cout << "Extend blend region collection" << std::endl; +#endif + for (size_t ki=0; ki<edges_.size(); ++ki) + { + extendBlendAssociation(ki); + } + + + int nmb_sfs = (int)surfaces_.size(); + defineSmallRegionSurfaces(); + +#ifdef DEBUG + for (size_t ki=0; ki<regions_.size(); ++ki) + { + RevEngRegion *first = regions_[ki]->getPoint(0)->region(); + int num = regions_[ki]->numPoints(); + for (int ka=1; ka<num; ++ka) + if (regions_[ki]->getPoint(ka)->region() != first) + std::cout << "Inconsistent region pointers, post defineSmallRegionSurfaces: " << ki << " " << ka << std::endl; + } +#endif + +#ifdef DEBUG + checkConsistence("Regions10_1"); + + if (regions_.size() > 0) + { + std::cout << "Regions10_1" << std::endl; + std::ofstream of("regions10_1.g2"); + std::ofstream ofm("mid_regions10_1.g2"); + std::ofstream ofs("small_regions10_1.g2"); + writeRegionStage(of, ofm, ofs); + + if (surfaces_.size() > 0) + { + std::ofstream of("regsurf10_1.g2"); + writeRegionWithSurf(of); + } + } + if (edges_.size() > 0) + { + std::ofstream ofe("edges10_1.g2"); + writeEdgeStage(ofe); + } + + if (surfaces_.size() > 0) + { + std::ofstream ofsf("surfaces10_1.g2"); + for (size_t kr=0; kr<surfaces_.size(); ++kr) + { + RevEngRegion *reg = surfaces_[kr]->getRegion(0); + reg->writeSurface(ofsf); + //reg->writeRegionPoints(ofsf); + } + } +#endif + + // Update adjacency between regions + for (size_t ki=0; ki<regions_.size(); ++ki) + { + regions_[ki]->clearRegionAdjacency(); + } + for (size_t ki=0; ki<regions_.size(); ++ki) + { + regions_[ki]->setRegionAdjacency(); + } + + // Check if small regions surfaces really belongs to a blend + for (size_t ki=nmb_sfs; ki<surfaces_.size();) + { + RevEngRegion *reg = surfaces_[ki]->getRegion(0); + vector<HedgeSurface*> removed_sfs; + reg->checkEdgeAssociation(approx_tol_, min_point_region_, removed_sfs); + if (removed_sfs.size() > 0) + { + for (size_t kr=0; kr<removed_sfs.size(); ++kr) + { + size_t kj; + for (kj=0; kj<surfaces_.size(); ++kj) + if (surfaces_[kj].get() == removed_sfs[kr]) + break; + if (kj < surfaces_.size()) + surfaces_.erase(surfaces_.begin()+kj); + } + } + else + ++ki; + } + +#ifdef DEBUG + for (int ki=0; ki<(int)regions_.size(); ++ki) + { + int num = regions_[ki]->numPoints(); + for (int ka=0; ka<num; ++ka) + if (regions_[ki]->getPoint(ka)->region() != regions_[ki].get()) + std::cout << "Inconsistent region pointers, post define small region surfaces: " << ki << " " << ka << std::endl; + } +#endif + // if ((int)surfaces_.size() > nmb_sfs) + // recognizeEdges(); + +#ifdef DEBUG + checkConsistence("Regions10_1_2"); + + if (regions_.size() > 0) + { + std::cout << "Regions10_1_2" << std::endl; + std::ofstream of("regions10_1_2.g2"); + std::ofstream ofm("mid_regions10_1_2.g2"); + std::ofstream ofs("small_regions10_1_2.g2"); + writeRegionStage(of, ofm, ofs); + + if (surfaces_.size() > 0) + { + std::ofstream of("regsurf10_1.g2"); + writeRegionWithSurf(of); + } + } + if (edges_.size() > 0) + { + std::ofstream ofe("edges10_1_2.g2"); + writeEdgeStage(ofe); + } +#endif + + double angtol = 5.0*anglim_; + for (int ka=nmb_sfs; ka<(int)surfaces_.size(); ++ka) + { + growSmallRegionSurface(ka); + } + //#if 0 + // Dismiss too small surfaces. First check connectivity + int min_sf_pts = min_point_region_/5; + for (int ka=0; ka<(int)regions_.size(); ++ka) + { + if ((!regions_[ka]->hasSurface()) || regions_[ka]->hasBlendEdge()) + continue; + vector<vector<RevEngPoint*> > separate_groups; + vector<HedgeSurface*> out_sfs; + vector<RevEngEdge*> out_edgs; + regions_[ka]->splitRegion(separate_groups); + if (separate_groups.size() > 0) + regions_[ka]->updateInfo(approx_tol_, angtol); + if (regions_[ka]->numPoints() < min_sf_pts) + { + out_sfs.push_back(regions_[ka]->getSurface(0)); + vector<RevEngEdge*> rev_edgs = regions_[ka]->getAllRevEdges(); + for (size_t kr=0; kr<rev_edgs.size(); ++kr) + { + RevEngRegion *adj1, *adj2; + rev_edgs[kr]->getAdjacent(adj1, adj2); + RevEngRegion *other = (adj1 == regions_[ka].get()) ? adj2 : adj1; + other->removeRevEngEdge(rev_edgs[kr]); + } + out_edgs.insert(out_edgs.end(), rev_edgs.begin(), rev_edgs.end()); + regions_[ka]->clearSurface(); + } + + if (separate_groups.size() > 0 || out_sfs.size() > 0) + surfaceExtractOutput(ka, separate_groups, out_sfs); + + for (size_t ki=0; ki<out_edgs.size(); ++ki) + { + size_t kj; + for (kj=0; kj<edges_.size(); ++kj) + if (edges_[kj].get() == out_edgs[ki]) + break; + if (kj < edges_.size()) + edges_.erase(edges_.begin()+kj); + } + + } + //#endif + recognizeEdges(); + + + +#ifdef DEBUG + checkConsistence("Regions10_2"); + + if (regions_.size() > 0) + { + std::cout << "Regions10_2" << std::endl; + std::ofstream of("regions10_2.g2"); + std::ofstream ofm("mid_regions10_2.g2"); + std::ofstream ofs("small_regions10_2.g2"); + writeRegionStage(of, ofm, ofs); + + if (surfaces_.size() > 0) + { + std::ofstream of("regsurf10_2.g2"); + writeRegionWithSurf(of); + } + } + if (edges_.size() > 0) + { + std::ofstream ofe("edges10_2.g2"); + writeEdgeStage(ofe); + } + if (surfaces_.size() > 0) + { + std::ofstream ofsf("surfaces10_2.g2"); + for (size_t kr=0; kr<surfaces_.size(); ++kr) + { + RevEngRegion *reg = surfaces_[kr]->getRegion(0); + reg->writeSurface(ofsf); + //reg->writeRegionPoints(ofsf); + } + } +#ifdef DEBUG + for (int ki=0; ki<(int)regions_.size(); ++ki) + { + int num = regions_[ki]->numPoints(); + for (int ka=0; ka<num; ++ka) + if (regions_[ki]->getPoint(ka)->region() != regions_[ki].get()) + std::cout << "Inconsistent region pointers, post grow small regions surfaces: " << ki << " " << ka << std::endl; + } +#endif + std::cout << "Define small region surfaces, regions: " << regions_.size() << ", surfaces: " << surfaces_.size() << std::endl; +#endif + int stop_break = 1; +} + +//=========================================================================== +// Service function for growSmallRegionSurface +int selectBestAccuracy(double tol, int num, double maxd[2], double avd[2], + int num_in[2], int num2_in[2]) +{ + int ix = (avd[0] < avd[1]) ? 0 : 1; + int ix2 = 1 - ix; + double fac = 1.1; + if ((avd[ix2] < fac*avd[ix] && num_in[ix2] > num_in[ix] && num2_in[ix2] > num_in[ix])) + std::swap(ix,ix2); + + return ix; +} + +//=========================================================================== +void RevEng::growSmallRegionSurface(int& ix) +//=========================================================================== +{ + double angtol = 5.0*anglim_; + + RevEngRegion *reg = surfaces_[ix]->getRegion(0); + shared_ptr<ParamSurface> surf = surfaces_[ix]->surface(); + bool cyllike = (surf->instanceType() == Class_Cylinder || + surf->instanceType() == Class_Cone); + int num_group_points = reg->numPoints(); + + // Collect feasible adjacent regions + vector<RevEngRegion*> adj_surf, adj_nosurf; + reg->getAdjCandMerge(adj_surf, adj_nosurf); + +#ifdef DEBUG_SMALL + std::ofstream of1("grow_small.g2"); + reg->writeRegionPoints(of1); + reg->writeSurface(of1); + + for (size_t kr=0; kr<adj_surf.size(); ++kr) + { + adj_surf[kr]->writeRegionPoints(of1); + adj_surf[kr]->writeSurface(of1); + } + + for (size_t kr=0; kr<adj_nosurf.size(); ++kr) + { + adj_nosurf[kr]->writeRegionPoints(of1); + } +#endif + + // Decide on master regions with surface + vector<RevEngRegion*> to_remove; + for (size_t ki=0; ki<adj_surf.size(); ++ki) + { + // Check combined accuracy based on current region and adjacent region + int numpt = reg->numPoints() + adj_surf[ki]->numPoints(); + double maxd[2], avd[2], maxd_loc[2], avd_loc[2]; + int num_in[2], num2_in[2], num_in_loc[2], num2_in_loc[2]; + vector<vector<double> > parvals(2); // Only points from the other region + vector<vector<pair<double,double> > > distang(2); + int sf_flag_loc[2]; + sf_flag_loc[0] = + reg->getGrowAccuracy(adj_surf[ki], approx_tol_, angtol, maxd[0], avd[0], + num_in[0], num2_in[0], maxd_loc[0], avd_loc[0], + num_in_loc[0], num2_in_loc[0], parvals[0], distang[0]); + sf_flag_loc[1] = + adj_surf[ki]->getGrowAccuracy(reg, approx_tol_, angtol, maxd[1], avd[1], + num_in[1], num2_in[1], maxd_loc[1], avd_loc[1], + num_in_loc[1], num2_in_loc[1], parvals[1], distang[1]); + + int m_ix = selectBestAccuracy(approx_tol_, numpt, maxd, avd, num_in, num2_in); + if (m_ix < 0 || sf_flag_loc[m_ix] == ACCURACY_POOR || sf_flag_loc[m_ix] == NOT_SET) + continue; + + shared_ptr<ParamSurface> surf2 = adj_surf[ki]->getSurface(0)->surface(); + bool cyllike2 = (surf2->instanceType() == Class_Cylinder || + surf2->instanceType() == Class_Cone); + int sf_flag = reg->defineSfFlag(numpt, 0, approx_tol_, num_in[m_ix], num2_in[m_ix], + avd[m_ix], (m_ix==0) ? cyllike : cyllike2); + if (sf_flag == ACCURACY_POOR || sf_flag == NOT_SET) + continue; + + vector<RevEngRegion*> added_adjacent; + if (m_ix == 0) + { + reg->includeAdjacentRegion(adj_surf[ki], maxd_loc[m_ix], avd_loc[m_ix], + num_in_loc[m_ix], num2_in_loc[ix], parvals[m_ix], + distang[m_ix], added_adjacent); + to_remove.push_back(adj_surf[ki]); + } + else + { + adj_surf[ki]->includeAdjacentRegion(reg, maxd_loc[m_ix], avd_loc[m_ix], + num_in_loc[m_ix], num2_in_loc[m_ix], + parvals[m_ix], distang[m_ix], added_adjacent); + to_remove.push_back(reg); + reg = adj_surf[ki]; + cyllike = cyllike2; + } + + reg->setSurfaceFlag(sf_flag); + int stop_break0 = 1; + } + + for (size_t ki=0; ki<adj_nosurf.size(); ++ki) + { + int numpt = reg->numPoints() + adj_nosurf[ki]->numPoints(); + double maxd, maxd_loc, avd, avd_loc; + int num_in, num2_in, num_in_loc, num2_in_loc; + vector<double> parvals; + vector<pair<double,double> > distang; + int sf_flag_loc = + reg->getGrowAccuracy(adj_nosurf[ki], approx_tol_, angtol, maxd, avd, + num_in, num2_in, maxd_loc, avd_loc, + num_in_loc, num2_in_loc, parvals, distang); + int sf_flag = reg->defineSfFlag(numpt, 0, approx_tol_, num_in, num2_in, + avd, cyllike); + if (sf_flag == ACCURACY_POOR || sf_flag == NOT_SET || + sf_flag_loc == ACCURACY_POOR || sf_flag_loc == NOT_SET) + continue; + + vector<RevEngRegion*> added_adjacent; + reg->includeAdjacentRegion(adj_nosurf[ki], maxd_loc, avd_loc, + num_in_loc, num2_in_loc, parvals, + distang, added_adjacent); + to_remove.push_back(adj_nosurf[ki]); + reg->setSurfaceFlag(sf_flag); + } + + vector<HedgeSurface*> to_remove_sfs; + vector<RevEngEdge*> to_remove_edg; + for (size_t ki=0; ki<to_remove.size(); ++ki) + { + if (to_remove[ki]->hasSurface()) + { + int numsf = to_remove[ki]->numSurface(); + for (int ka=0; ka<numsf; ++ka) + to_remove_sfs.push_back(to_remove[ki]->getSurface(ka)); + } + vector<RevEngEdge*> rev_edgs = to_remove[ki]->getAllRevEdges(); + for (size_t kr=0; kr<rev_edgs.size(); ++kr) + { + RevEngRegion *adj1, *adj2; + rev_edgs[kr]->getAdjacent(adj1, adj2); + RevEngRegion *other = (adj1 == to_remove[ki]) ? adj2 : adj1; + other->removeRevEngEdge(rev_edgs[kr]); + } + to_remove_edg.insert(to_remove_edg.end(), rev_edgs.begin(), rev_edgs.end()); + to_remove[ki]->removeFromAdjacent(); + to_remove[ki]->clearRegionAdjacency(); + } + + double fac = 1.5; + if (reg->numPoints() > (int)(fac*num_group_points) || + to_remove_sfs.size() > 0) + { + vector<RevEngEdge*> rev_edges_curr = reg->getAllRevEdges(); + for (size_t kj=0; kj<rev_edges_curr.size(); ++kj) + rev_edges_curr[kj]->increaseExtendCount(); + } + + for (size_t ki=0; ki<to_remove_sfs.size(); ++ki) + { + size_t kj; + for (kj=0; kj<surfaces_.size(); ++kj) + if (surfaces_[kj].get() == to_remove_sfs[ki]) + break; + if ((int)kj <= ix) + --ix; + } + + for (size_t ki=0; ki<to_remove_edg.size(); ++ki) + { + size_t kj; + for (kj=0; kj<edges_.size(); ++kj) + if (edges_[kj].get() == to_remove_edg[ki]) + break; + if (kj < edges_.size()) + edges_.erase(edges_.begin()+kj); + } + + if (to_remove.size() > 0) + { + for (size_t ki=0; ki<to_remove.size(); ++ki) + { + to_remove[ki]->removeFromAdjacent(); + to_remove[ki]->clearRegionAdjacency(); + } + + int dummy_ix = -1; + updateRegionsAndSurfaces(dummy_ix, to_remove, to_remove_sfs); + } + +#ifdef DEBUG_SMALL + std::ofstream of2("updated_small.g2"); + reg->writeRegionPoints(of2); + reg->writeSurface(of2); +#endif + int stop_break = 1; +} + +//=========================================================================== +// Service functionality for defineSmallRegionSurfaces +// + +void groupAdjacentRegions(vector<RevEngRegion*>& regs, + vector<vector<RevEngRegion*> >& groups, + vector<int>& num_group) +{ + for (size_t kh=0; kh<regs.size(); ++kh) + { + vector<RevEngRegion*> currgroup; + if (regs[kh]->visited()) + continue; + regs[kh]->setVisited(true); + currgroup.push_back(regs[kh]); + for (size_t kh2=0; kh2<currgroup.size(); ++kh2) + { + RevEngRegion *curr=currgroup[kh2]; + vector<RevEngRegion*> adjacent; + curr->getAdjacentRegions(adjacent); + for (size_t kh3=0; kh3<adjacent.size(); ++kh3) + { + if (adjacent[kh3]->visited()) + continue; + if (adjacent[kh3]->hasSurface()) + continue; + if (adjacent[kh3]->hasAssociatedBlend()) + continue; + size_t kh4; + for (kh4=0; kh4<regs.size(); ++kh4) + if (adjacent[kh3] == regs[kh4]) + break; + if (kh4 < regs.size()) + { + adjacent[kh3]->setVisited(true); + currgroup.push_back(adjacent[kh3]); + } + } + } + groups.push_back(currgroup); + } + + for (size_t kh=0; kh<regs.size(); ++kh) + regs[kh]->setVisited(false); + + num_group.resize(groups.size(), 0); + for (size_t kr=0; kr<groups.size(); ++kr) + for (size_t kh=0; kh<groups[kr].size(); ++kh) + num_group[kr] += groups[kr][kh]->numPoints(); +} + +void disconnectRegion(RevEngRegion* reg, vector<RevEngRegion*>& removed_regs, + vector<shared_ptr<RevEngRegion> >& added_regs, + vector<RevEngRegion*>& nosf_reg) +{ + reg->removeFromAdjacent(); + reg->clearRegionAdjacency(); + auto it = std::find(nosf_reg.begin(), nosf_reg.end(), reg); + if (it != nosf_reg.end()) + nosf_reg.erase(it); + size_t ki; + for (ki=0; ki<added_regs.size(); ++ki) + if (added_regs[ki].get() == reg) + break; + if (ki == added_regs.size()) + removed_regs.push_back(reg); + else + added_regs.erase(added_regs.begin()+ki); + } + + +void sortAlongAxis(vector<RevEngPoint*>& points, const Point& pos, + const Point& axis, vector<double>& ppar, double delta, + vector<vector<RevEngPoint*> >& sorted, size_t nsort, + vector<pair<RevEngPoint*, double> >& remaining, + double& tmin, double& tmax) + { + tmin = std::numeric_limits<double>::max(); + tmax = std::numeric_limits<double>::lowest(); + for (size_t ki=0; ki<points.size(); ++ki) + { + Vector3D xyz = points[ki]->getPoint(); + Point point(xyz[0], xyz[1], xyz[2]); + double tpar = (point - pos)*axis; + tmin = std::min(tmin, tpar); + tmax = std::max(tmax, tpar); + + if (ppar.size() == 0) + { + sorted[nsort].push_back(points[ki]); + } + else + { + size_t kr; + for (kr=0; kr<ppar.size() && ppar[kr]<tpar; ++kr); + if (kr > 0 && kr == ppar.size()) + --kr; + if (fabs(tpar-ppar[kr]) < delta || (kr>0 && fabs(tpar-ppar[kr-1]) < delta) || + (kr < ppar.size()-1 && fabs(tpar-ppar[kr+1]) < delta)) + remaining.push_back(std::make_pair(points[ki],tpar)); + else if (tpar < ppar[0]-delta) + sorted[nsort].push_back(points[ki]); + else if (tpar > ppar[ppar.size()-1]+delta) + sorted[nsort+ppar.size()].push_back(points[ki]); + else + sorted[nsort+kr].push_back(points[ki]); + } + } + } + +BoundingBox bBoxGroup(vector<RevEngPoint*>& group) +{ + BoundingBox bbox(3); + for (size_t ki=0; ki<group.size(); ++ki) + { + Vector3D xyz = group[ki]->getPoint(); + Point pnt(xyz[0], xyz[1], xyz[2]); + bbox.addUnionWith(pnt); + } + return bbox; +} + +//=========================================================================== +void RevEng::defineSmallRegionSurfaces() +//=========================================================================== +{ + if (model_axis_.size() == 0) + return; + +#ifdef DEBUG_SMALL + std::ofstream of1("nosurf_reg.g2"); + std::ofstream of1_2("withsurf_reg.g2"); + std::ofstream of1_3("assblend_reg.g2"); +#endif + + vector<RevEngRegion*> nosf_reg; + for (size_t kr=0; kr<regions_.size(); ++kr) + { + if (regions_[kr]->hasSurface()) + { +#ifdef DEBUG_SMALL + regions_[kr]->writeRegionPoints(of1_2); +#endif + continue; + } + if (regions_[kr]->hasAssociatedBlend()) + { +#ifdef DEBUG_SMALL + regions_[kr]->writeRegionPoints(of1_3); +#endif + continue; + } +#ifdef DEBUG_SMALL + regions_[kr]->writeRegionPoints(of1); +#endif + nosf_reg.push_back(regions_[kr].get()); + } + + // Sort according to identified planes + double angtol = 5.0*anglim_; + int num_pt_lim = min_point_region_/3; + double axisang = 2.0*angtol; + double planeang = angtol; + + double diag = bbox_.low().dist(bbox_.high()); + + // Count surfaces and points associated to each model axis + size_t num_model_axis = model_axis_.size(); + vector<int> n_msurf(num_model_axis, 0), n_mpts(num_model_axis, 0); + for (size_t ki=0; ki<num_model_axis; ++ki) + { + n_msurf[ki] += ((int)model_axis_[ki].plane_loc_.size() + + (int)model_axis_[ki].rotational_loc_.size()); + for (size_t kj=0; kj<model_axis_[ki].plane_loc_.size(); ++kj) + n_mpts[ki] += model_axis_[ki].plane_loc_[kj].second; + for (size_t kj=0; kj<model_axis_[ki].rotational_loc_.size(); ++kj) + n_mpts[ki] += model_axis_[ki].rotational_loc_[kj].second; + } + + double allnsurf = 0.0; + double allnpt = 0.0; + double lim1 = 0.5, lim2 = 0.25, lim3 = 0.1; + for (size_t ki=0; ki<num_model_axis; ++ki) + { + allnsurf += n_msurf[ki]; + allnpt += n_mpts[ki]; + } + + vector<size_t> axis_split; + axis_split.push_back(0); + size_t kia; + for (kia=0; kia<n_msurf.size() && (double)n_msurf[kia] >= lim1*(double)allnsurf && + (double)n_mpts[kia] >= lim1*(double)allnpt; ++kia); + if (kia > axis_split[axis_split.size()-1]) + axis_split.push_back(kia); + for (; kia<n_msurf.size() && (double)n_msurf[kia] >= lim2*(double)allnsurf && + (double)n_mpts[kia] >= lim2*(double)allnpt; ++kia); + if (kia > axis_split[axis_split.size()-1]) + axis_split.push_back(kia); + for (; kia<n_msurf.size() && (double)n_msurf[kia] >= lim3*(double)allnsurf && + (double)n_mpts[kia] >= lim3*(double)allnpt; ++kia); + if (kia > axis_split[axis_split.size()-1]) + axis_split.push_back(kia); + if (num_model_axis > axis_split[axis_split.size()-1]) + axis_split.push_back(num_model_axis); + + for (size_t ax=1; ax<axis_split.size(); ++ax) + { + size_t ax1 = axis_split[ax-1]; + size_t ax2 = axis_split[ax]; + + // Extract points according to identified axes and differ between planar + // and rotational candidates + vector<Point> axis_dir(ax2-ax1); + for (size_t ki=ax1; ki<ax2; ++ki) + axis_dir[ki-ax1] = model_axis_[ki].axis_; + + vector<vector<RevEngPoint*> > axis_group1(2*axis_dir.size()); + vector<vector<RevEngPoint*> > axis_group2(axis_dir.size()); + vector<RevEngPoint*> remaining; + for (size_t ki=0; ki<nosf_reg.size(); ++ki) + { + vector<vector<RevEngPoint*> > curr_group1, curr_group2; + vector<RevEngPoint*> curr_remaining; + (void)nosf_reg[ki]->sortByAxis(axis_dir, approx_tol_, axisang, planeang, + curr_group1, curr_group2, curr_remaining); + for (size_t kr=0; kr<curr_group1.size(); ++kr) + if (curr_group1[kr].size() > 0) + axis_group1[kr].insert(axis_group1[kr].end(), curr_group1[kr].begin(), + curr_group1[kr].end()); + for (size_t kr=0; kr<curr_group2.size(); ++kr) + if (curr_group2.size() > 0) + axis_group2[kr].insert(axis_group2[kr].end(), curr_group2[kr].begin(), + curr_group2[kr].end()); + if (curr_remaining.size() > 0) + remaining.insert(remaining.end(), curr_remaining.begin(), curr_remaining.end()); + } + +#ifdef DEBUG_SMALL + std::ofstream of2("small_axis_sort.g2"); + for (size_t kr=0; kr<axis_group1.size(); kr+=2) + { + if (axis_group1[kr].size() > 0) + { + of2 << "400 1 0 4 0 255 0 255" << std::endl; + of2 << axis_group1[kr].size() << std::endl; + for (size_t kw=0; kw<axis_group1[kr].size(); ++kw) + of2 << axis_group1[kr][kw]->getPoint() << std::endl; + } + if (axis_group1[kr+1].size() > 0) + { + of2 << "400 1 0 4 100 155 0 255" << std::endl; + of2 << axis_group1[kr+1].size() << std::endl; + for (size_t kw=0; kw<axis_group1[kr+1].size(); ++kw) + of2 << axis_group1[kr+1][kw]->getPoint() << std::endl; + } + } + + for (size_t kr=0; kr<axis_group2.size(); ++kr) + { + if (axis_group2[kr].size() > 0) + { + of2 << "400 1 0 4 255 0 0 255" << std::endl; + of2 << axis_group2[kr].size() << std::endl; + for (size_t kw=0; kw<axis_group2[kr].size(); ++kw) + of2 << axis_group2[kr][kw]->getPoint() << std::endl; + } + } + + if (remaining.size() > 0) + { + of2 << "400 1 0 4 0 0 255 255" << std::endl; + of2 << remaining.size() << std::endl; + for (size_t kw=0; kw<remaining.size(); ++kw) + of2 << remaining[kw]->getPoint() << std::endl; + } + +#endif + + // Sort according to identified axis and planes + vector<SmallSurface> small_surf; + vector<shared_ptr<RevEngRegion> > small_sf_reg; + vector<shared_ptr<HedgeSurface> > small_sf_hedge; + for (size_t ki=ax1, ki2=0; ki<ax2; ++ki, ++ki2) + { + if (n_mpts[ki] < min_point_region_) + continue; + size_t num_planes = model_axis_[ki].plane_loc_.size(); + Point axis = model_axis_[ki].axis_; + vector<shared_ptr<Plane> > axis_planes; + + if (num_planes > 0) + { + axis_planes.resize(num_planes); + for (size_t kr=0; kr<num_planes; ++kr) + axis_planes[kr] = shared_ptr<Plane>(new Plane(model_axis_[ki].plane_loc_[kr].first, + axis)); +#ifdef DEBUG_SMALL + std::ofstream of4("axis_planes.g2"); + for (size_t kr=0; kr<num_planes; ++kr) + { + shared_ptr<Plane> tmp_plane(axis_planes[kr]->clone()); + tmp_plane->setParameterBounds(-0.5*diag, -0.5*diag, 0.5*diag, 0.5*diag); + tmp_plane->writeStandardHeader(of4); + tmp_plane->write(of4); + } +#endif + } + int ix = -1; + double minang = std::numeric_limits<double>::max(); + for (int kb=0; kb<3; ++kb) + { + double ang = mainaxis_[kb].angle(axis); + ang = std::min(ang, M_PI-ang); + if (ang < minang) + { + minang = ang; + ix = kb; + } + } + ix = (ix > 0) ? ix-1 : 2; + Point Cx = mainaxis_[ix].cross(axis); + Cx.normalize(); + + Point midp(0.0, 0.0, 0.0); + vector<double> ppar; + double delta = 0.0001; + if (num_planes > 0) + { + double fac = 1.0/(double)(num_planes); + for (size_t kj=0; kj<num_planes; ++kj) + midp += fac*model_axis_[ki].plane_loc_[kj].first; + + ppar.resize(num_planes); + for (size_t kj=0; kj<num_planes; ++kj) + ppar[kj] = (model_axis_[ki].plane_loc_[kj].first - midp)*axis; + + // Sort locations along axis + for (size_t kj=0; kj<ppar.size(); ++kj) + for (size_t kr=kj+1; kr<ppar.size(); ++kr) + if (ppar[kr] < ppar[kj]) + { + std::swap(ppar[kj], ppar[kr]); + std::swap(axis_planes[kj], axis_planes[kr]); + } + delta = std::max(delta, 0.01*(ppar[ppar.size()-1]-ppar[0])); + } + + size_t nsort = ppar.size()+1; + vector<vector<RevEngPoint*> > planar_cand(2*nsort); + vector<vector<RevEngPoint*> > rotational_cand(nsort); + vector<pair<RevEngPoint*,double> > at_planes; + double tmin, tmax; + double all_min = std::numeric_limits<double>::max(); + double all_max = std::numeric_limits<double>::lowest(); + sortAlongAxis(axis_group1[2*ki2], midp, axis_dir[ki2], ppar, delta, + planar_cand, 0, at_planes, tmin, tmax); + all_min = std::min(all_min, tmin); + all_max = std::max(all_max, tmax); + sortAlongAxis(axis_group1[2*ki2+1], midp, axis_dir[ki2], ppar, delta, + planar_cand, nsort, at_planes, tmin, tmax); + all_min = std::min(all_min, tmin); + all_max = std::max(all_max, tmax); + sortAlongAxis(axis_group2[ki2], midp, axis_dir[ki2], ppar, delta, + rotational_cand, 0, at_planes, tmin, tmax); + all_min = std::min(all_min, tmin); + all_max = std::max(all_max, tmax); + ppar.insert(ppar.begin(), all_min-delta); + ppar.push_back(all_max+delta); + +#ifdef DEBUG_SMALL + std::ofstream of14("at_planes.g2"); + of14 << "400 1 0 4 100 0 155 255" << std::endl; + of14 << at_planes.size() << std::endl; + for (size_t kw=0; kw<at_planes.size(); ++kw) + of14 << at_planes[kw].first->getPoint() << std::endl; +#endif + + int min_point_reg2 = std::max(min_point_region_/10, 200); + int min_point_reg3 = std::max(min_point_region_/20, 200); + for (size_t kr=0; kr<rotational_cand.size(); ++kr) + { + +#ifdef DEBUG_SMALL + std::ofstream of3("small_plane_int.g2"); + if (planar_cand[kr].size() > 0) + { + of3 << "400 1 0 4 0 255 0 255" << std::endl; + of3 << planar_cand[kr].size() << std::endl; + for (size_t kw=0; kw<planar_cand[kr].size(); ++kw) + of3 << planar_cand[kr][kw]->getPoint() << std::endl; + } + + if (planar_cand[nsort+kr].size() > 0) + { + of3 << "400 1 0 4 100 155 0 255" << std::endl; + of3 << planar_cand[nsort+kr].size() << std::endl; + for (size_t kw=0; kw<planar_cand[nsort+kr].size(); ++kw) + of3 << planar_cand[nsort+kr][kw]->getPoint() << std::endl; + } + + if (rotational_cand[kr].size() > 0) + { + of3 << "400 1 0 4 255 0 0 255" << std::endl; + of3 << rotational_cand[kr].size() << std::endl; + for (size_t kw=0; kw<rotational_cand[kr].size(); ++kw) + of3 << rotational_cand[kr][kw]->getPoint() << std::endl; + } +#endif + // Start with rotational + if (rotational_cand[kr].size() >= min_point_reg2) //num_pt_lim) //min_point_region_) + { + // Group adjacent + vector<vector<RevEngPoint*> > rot_groups; + RevEngUtils::identifyConGroups(rotational_cand[kr], rot_groups); +#ifdef DEBUG_SMALL + std::ofstream of5("con_rotate.g2"); + for (size_t kh=0; kh<rot_groups.size(); ++kh) + { + of5 << "400 1 0 0" << std::endl; + of5 << rot_groups[kh].size() << std::endl; + for (size_t kv=0; kv<rot_groups[kh].size(); ++kv) + of5 << rot_groups[kh][kv]->getPoint() << std::endl; + } +#endif + + for (size_t kh=0; kh<rot_groups.size(); ++kh) + { + BoundingBox bb = bBoxGroup(rot_groups[kh]); + Point high = bb.high(); + Point low = bb.low(); + for (size_t kv=0; kv<=model_axis_[ki].rotational_loc_.size(); ++kv) + { + Point loc; + if (kv < model_axis_[ki].rotational_loc_.size()) + loc = model_axis_[ki].rotational_loc_[kv].first; + // Point low2 = loc + ((low-loc)*axis)*axis; + // Point high2 = loc + ((high-loc)*axis)*axis; + // if ((low-low2)*(high-high2) > 0.0 && + // std::min(low.dist(low2), high.dist(high2)) > low.dist(high)) + // continue; // Large distance between points and axis + + // Check if the group can be associated any of the existing + // surfaces + size_t kj; + for (kj=0; kj<small_surf.size(); ++kj) + { + if ((int)ki != small_surf[kj].axis_ix_ || + (int)kr != small_surf[kj].lev_ix_ || + (int)kv != small_surf[kj].pos_ix_) + continue; // Not the same axis or interval + + if (small_surf[kj].type_ != 3) + continue; // Surface type not compatible + + // Test distance + int all_in = 0, all_in2 = 0; + for (size_t kw=0; kw<small_surf[kj].surfs_.size(); ++kw) + { + double maxdist, avdist; + int num_in, num2_in; + vector<pair<double, double> > dist_ang; + shared_ptr<ParamSurface> sf = small_surf[kj].surfs_[kw]; + RevEngUtils::distToSurf(rot_groups[kh], sf, + approx_tol_, angtol, maxdist, avdist, + num_in, num2_in, dist_ang); + all_in += num_in; + all_in2 += num2_in; + } + if (all_in2 >= std::max((int)rot_groups[kh].size()/2, 1)) + break; // Preliminary match found + } + + if (kj < small_surf.size()) + { + small_surf[kj].addPoints(rot_groups[kh], bb); + break; + } + + // Try to adapt a rotational surface + if ((int)rot_groups[kh].size() < min_point_reg3) + continue; + + vector<shared_ptr<ElementarySurface> > sfs; + bool found = identifySmallRotational(rot_groups[kh], midp, loc, + axis, Cx, + ppar[kr], ppar[kr+1], sfs); + if (found) + { +#ifdef DEBUG_SMALL + std::ofstream of6("rot_sfs.g2"); + for (size_t kw=0; kw<sfs.size(); ++kw) + { + sfs[kw]->writeStandardHeader(of6); + sfs[kw]->write(of6); + } +#endif + + SmallSurface small((int)ki, (int)kv, (int)kr, 3, sfs); + small.addPoints(rot_groups[kh], bb); + small_surf.push_back(small); + break; + } + int stop_break = 1; + } + } + } + + // Planar + for (int ka=0; ka<2; ++ka) + { + if (planar_cand[ka*nsort+kr].size() < min_point_reg2) //num_pt_lim) //min_point_region_) + continue; + + // Group adjacent + vector<vector<RevEngPoint*> > pla_groups; + RevEngUtils::identifyConGroups(planar_cand[ka*nsort+kr], pla_groups); +#ifdef DEBUG_SMALL + std::ofstream of9("pla_groups.g2"); + for (size_t kh=0; kh<pla_groups.size(); ++kh) + { + of9 << "400 1 0 0" << std::endl; + of9 << pla_groups[kh].size() << std::endl; + for (size_t kv=0; kv<pla_groups[kh].size(); ++kv) + of9 << pla_groups[kh][kv]->getPoint() << std::endl; + } +#endif + + for (size_t kh=0; kh<pla_groups.size(); ++kh) + { + BoundingBox bb = bBoxGroup(pla_groups[kh]); + Point high = bb.high(); + Point low = bb.low(); + + // Check if the group can be associated any of the existing + // surfaces + size_t kj; + for (kj=0; kj<small_surf.size(); ++kj) + { + if ((int)ki != small_surf[kj].axis_ix_ || + (int)kr != small_surf[kj].lev_ix_) + continue; // Not the same axis or interval + + if (small_surf[kj].type_ != ka+1) + continue; // Surface type not compatible + + // Test distance + int all_in = 0, all_in2 = 0; + for (size_t kw=0; kw<small_surf[kj].surfs_.size(); ++kw) + { + double maxdist, avdist; + int num_in, num2_in; + vector<pair<double, double> > dist_ang; + shared_ptr<ParamSurface> sf = small_surf[kj].surfs_[kw]; + RevEngUtils::distToSurf(pla_groups[kh], sf, + approx_tol_, angtol, maxdist, avdist, + num_in, num2_in, dist_ang); + all_in += num_in; + all_in2 += num2_in; + } + if (all_in2 >= std::max((int)pla_groups[kh].size()/2, 1)) + break; // Prelimenary match found + } + + if (kj < small_surf.size()) + { + small_surf[kj].addPoints(pla_groups[kh], bb); + continue; + } + + // Try to adapt a planar surface + if ((int)pla_groups[kh].size() < min_point_reg3) + continue; + + vector<shared_ptr<ElementarySurface> > sfs; + bool found = identifySmallPlanar(pla_groups[kh], midp, axis, Cx, + ppar[kr], ppar[kr+1], delta, sfs); + if (found) + { +#ifdef DEBUG_SMALL + std::ofstream of9("pla_sfs.g2"); + for (size_t kw=0; kw<sfs.size(); ++kw) + { + sfs[kw]->writeStandardHeader(of9); + sfs[kw]->write(of9); + } +#endif + + SmallSurface small((int)ki, -1, (int)kr, ka+1, sfs); + small.addPoints(pla_groups[kh], bb); + small_surf.push_back(small); + } + int stop_break = 1; + } + } +#ifdef DEBUG_SMALL + std::ofstream of8("small_sfs_curr.g2"); + for (size_t kv=0; kv<small_surf.size(); ++kv) + { + if (small_surf[kv].lev_ix_ != (int)kr) + continue; + for (size_t kw=0; kw<small_surf[kv].surfs_.size(); ++kw) + { + small_surf[kv].surfs_[kw]->writeStandardHeader(of8); + small_surf[kv].surfs_[kw]->write(of8); + } + for (size_t kw=0; kw<small_surf[kv].assos_points_.size(); ++kw) + { + of8 << "400 1 0 0" << std::endl; + of8 << small_surf[kv].assos_points_[kw].size() << std::endl; + for (size_t kw2=0; kw2<small_surf[kv].assos_points_[kw].size(); ++kw2) + of8 << small_surf[kv].assos_points_[kw][kw2]->getPoint() << std::endl; + } + } +#endif + int stop_break3 = 1; + } + +#ifdef DEBUG_SMALL + std::ofstream of7("small_sfs_axis.g2"); + for (size_t kv=0; kv<small_surf.size(); ++kv) + { + for (size_t kw=0; kw<small_surf[kv].surfs_.size(); ++kw) + { + small_surf[kv].surfs_[kw]->writeStandardHeader(of7); + small_surf[kv].surfs_[kw]->write(of7); + } + for (size_t kw=0; kw<small_surf[kv].assos_points_.size(); ++kw) + { + of7 << "400 1 0 0" << std::endl; + of7 << small_surf[kv].assos_points_[kw].size() << std::endl; + for (size_t kw2=0; kw2<small_surf[kv].assos_points_[kw].size(); ++kw2) + of7 << small_surf[kv].assos_points_[kw][kw2]->getPoint() << std::endl; + } + } +#endif + // Associate near-plane points to existing planes or create new + // planes as appopriate + for (size_t kj=0; kj<axis_planes.size(); ++kj) + { + double tpar = ppar[kj+1]; + vector<RevEngPoint*> plane_pts; + for (size_t kr=0; kr<at_planes.size(); ++kr) + if (fabs(at_planes[kr].second - tpar) <= delta) + plane_pts.push_back(at_planes[kr].first); + + Point loc = axis_planes[kj]->location(); + Point norm = axis_planes[kj]->direction(); + vector<HedgeSurface*> hedge_surf; + for (size_t kr=0; kr<surfaces_.size(); ++kr) + { + shared_ptr<ParamSurface> surf = surfaces_[kr]->surface(); + if (surf->instanceType() != Class_Plane) + continue; + shared_ptr<Plane> plane = dynamic_pointer_cast<Plane,ParamSurface>(surf); + Point loc2 = plane->location(); + Point norm2 = plane->direction(); + double ang = norm.angle(norm2); + ang = std::min(ang, M_PI-ang); + double dist = (loc2 - loc)*norm; + if (ang <= angtol && fabs(dist) <= approx_tol_) + hedge_surf.push_back(surfaces_[kr].get()); + } +#ifdef DEBUG_SMALL + std::ofstream of15("at_curr_planes.g2"); + of15 << "400 1 0 4 0 255 0 255" << std::endl; + of15 << plane_pts.size() << std::endl; + for (size_t kv=0; kv<plane_pts.size(); ++kv) + of15 << plane_pts[kv]->getPoint() << std::endl; + for (size_t kv=0; kv<hedge_surf.size(); ++kv) + { + RevEngRegion *reg = hedge_surf[kv]->getRegion(0); + reg->writeRegionPoints(of15); + reg->writeSurface(of15); + } +#endif + size_t curr_nmb_small = small_sf_reg.size(); + planarAtPlane(axis_planes[kj], plane_pts, hedge_surf, small_sf_reg, + small_sf_hedge); +#ifdef DEBUG_SMALL + std::ofstream of16("at_curr_planes2.g2"); + for (size_t kv=0; kv<hedge_surf.size(); ++kv) + { + if (!hedge_surf[kv]) + continue; + RevEngRegion *reg = hedge_surf[kv]->getRegion(0); + reg->writeRegionPoints(of16); + if (reg->hasSurface()) + reg->writeSurface(of16); + } + for (size_t kv=curr_nmb_small; kv<small_sf_reg.size(); ++kv) + { + small_sf_reg[kv]->writeRegionPoints(of16); + small_sf_reg[kv]->writeSurface(of16); + } +#endif + + int stop_plane = 0; + } + + int stop_break2 = 1; + } + + vector<vector<RevEngPoint*> > remain_groups; + RevEngUtils::identifyConGroups(remaining, remain_groups); +#ifdef DEBUG_SMALL + std::ofstream ofr("con_remain.g2"); + for (size_t kh=0; kh<remain_groups.size(); ++kh) + { + ofr << "400 1 0 0" << std::endl; + ofr << remain_groups[kh].size() << std::endl; + for (size_t kv=0; kv<remain_groups[kh].size(); ++kv) + ofr << remain_groups[kh][kv]->getPoint() << std::endl; + } +#endif + + for (size_t kh=0; kh<remain_groups.size(); ++kh) + { + if ((int)remain_groups[kh].size() < num_pt_lim) + continue; + vector<RevEngPoint*> in_pts, out_pts; + BoundingBox bb; + shared_ptr<ElementarySurface> elem = + defineElemSurf(remain_groups[kh], in_pts, bb, out_pts); + if (elem.get()) + { + vector<shared_ptr<ElementarySurface> > sfs; + sfs.push_back(elem); +#ifdef DEBUG_SMALL + std::ofstream ofe("elem_remain_sf.g2"); + for (size_t kw=0; kw<sfs.size(); ++kw) + { + sfs[kw]->writeStandardHeader(ofe); + sfs[kw]->write(ofe); + } +#endif + + SmallSurface small(-1, -1, -1, 4, sfs); + small.addPoints(remain_groups[kh], bb); + small_surf.push_back(small); + } + int stop_break_elem = 1; + } + + + // Extract identified surfaces + vector<RevEngPoint*> non_assigned_pts; + for (size_t kj=0; kj<small_surf.size(); ++kj) + { + extractSmallSurfs(small_surf[kj], small_sf_reg, small_sf_hedge, + nosf_reg, non_assigned_pts); + } + + // Remove empty regions + for (int ka=(int)nosf_reg.size()-1; ka>=0; --ka) + if (nosf_reg[ka]->numPoints() == 0) + { + for (int kb=(int)regions_.size()-1; kb>=0; --kb) + if (regions_[kb].get() == nosf_reg[ka]) + { + regions_.erase(regions_.begin()+kb); + break; + } + nosf_reg.erase(nosf_reg.begin()+ka); + } +#ifdef DEBUG_SMALL + std::ofstream of10("all_small_sfs.g2"); + for (size_t kj=0; kj<small_sf_reg.size(); ++kj) + { + small_sf_reg[kj]->writeRegionPoints(of10); + small_sf_reg[kj]->writeSurface(of10); + } + std::ofstream of11("nosurf_reg2.g2"); + for (size_t kj=0; kj<nosf_reg.size(); ++kj) + nosf_reg[kj]->writeRegionPoints(of11); +#endif + + // Ensure connectivity of remaining small regions + vector<shared_ptr<RevEngRegion> > nosf_add; + size_t nmb_nosf = nosf_reg.size(); + for (size_t kj=0; kj<nosf_reg.size(); ++kj) + { + vector<vector<RevEngPoint*> > tmp_add; + int classtype = nosf_reg[kj]->getClassificationType(); + nosf_reg[kj]->splitRegion(tmp_add); + for (size_t kr=0; kr<tmp_add.size(); ++kr) + { + shared_ptr<RevEngRegion> tmp_reg(new RevEngRegion(classtype, + edge_class_type_, + tmp_add[kr])); + nosf_add.push_back(tmp_reg); + } + } + + for (size_t kj=0; kj<nosf_add.size(); ++kj) + nosf_reg.push_back(nosf_add[kj].get()); + +#ifdef DEBUG_SMALL + std::ofstream of12("nosurf_reg3.g2"); + for (size_t kj=0; kj<nosf_reg.size(); ++kj) + nosf_reg[kj]->writeRegionPoints(of12); +#endif + + vector<RevEngRegion*> include_reg; + integrateInSmallSurfs(small_sf_reg, nosf_reg, include_reg); + for (size_t kj=0; kj<include_reg.size(); ++kj) + { + include_reg[kj]->removeFromAdjacent(); + include_reg[kj]->clearRegionAdjacency(); + } + for (int ka=(int)include_reg.size()-1; ka>=0; --ka) + { + auto it = std::find(nosf_reg.begin(), nosf_reg.end(), include_reg[ka]); + if (it == nosf_reg.end()) + continue; // Should not happen + int ix = it - nosf_reg.begin(); + if (ix >= (int)nmb_nosf) + { + // nosf_add[ix-(int)nmb_nosf]->removeFromAdjacent(); + // nosf_add[ix-(int)nmb_nosf]->clearRegionAdjacency(); + nosf_add.erase(nosf_add.begin()+ix-(int)nmb_nosf); + } + else + { + for (int kb=(int)regions_.size()-1; kb>=0; --kb) + if (regions_[kb].get() == include_reg[ka]) + { + // regions_[kb]->removeFromAdjacent(); + // regions_[kb]->clearRegionAdjacency(); + regions_.erase(regions_.begin()+kb); + break; + } + nmb_nosf--; + } + nosf_reg.erase(nosf_reg.begin()+ix); + } + +#ifdef DEBUG_SMALL + std::ofstream of13("all_small_sfs2.g2"); + for (size_t kj=0; kj<small_sf_reg.size(); ++kj) + { + small_sf_reg[kj]->writeRegionPoints(of13); + small_sf_reg[kj]->writeSurface(of13); + } + std::ofstream of14("nosurf_reg4.g2"); + for (size_t kj=0; kj<nosf_reg.size(); ++kj) + nosf_reg[kj]->writeRegionPoints(of14); +#endif + + if (small_sf_reg.size() > 0) + regions_.insert(regions_.end(), small_sf_reg.begin(), small_sf_reg.end()); + if (nosf_add.size() > 0) + regions_.insert(regions_.end(), nosf_add.begin(), nosf_add.end()); + if (small_sf_hedge.size() > 0) + surfaces_.insert(surfaces_.end(), small_sf_hedge.begin(), small_sf_hedge.end()); + } +} + +//=========================================================================== +struct FittingResults +{ + double maxd, avd; + int inside, inside_2; + vector<double> param; + vector<pair<double,double> > distang; +}; + +void collectAdjacentSurfRegs(vector<RevEngPoint*>& points, + vector<pair<RevEngRegion*, int> >& adj_regs) +{ + for (size_t ki=0; ki<points.size(); ++ki) + { + vector<RevEngRegion*> adj = points[ki]->adjacentRegsWithSurf(); + for (size_t kj=0; kj<adj.size(); ++kj) + { + size_t kr; + for (kr=0; kr<adj_regs.size(); ++kr) + if (adj_regs[kr].first == adj[kj]) + break; + if (kr < adj_regs.size()) + adj_regs[kr].second++; + else + adj_regs.push_back(std::make_pair(adj[kj], 1)); + } + } +} + +double mostCompatibleDir(const Point& curr, vector<Point>& vecs1, + vector<Point>& vecs2, Point& dir) +{ + double min_ang = M_PI; + for (size_t ki=0; ki<vecs1.size(); ++ki) + { + double ang = curr.angle(vecs1[ki]); + ang = std::min(ang, M_PI-ang); + if (ang < min_ang) + { + min_ang = ang; + dir = vecs1[ki]; + } + } + for (size_t ki=0; ki<vecs2.size(); ++ki) + { + double ang = curr.angle(vecs2[ki]); + ang = std::min(ang, M_PI-ang); + if (ang < min_ang) + { + min_ang = ang; + dir = vecs2[ki]; + } + } + return min_ang; +} + +void identifyDistPoints(vector<RevEngPoint*>& points, vector<pair<double,double> >& distang, + double lim, vector<RevEngPoint*>& in_pts, + vector<RevEngPoint*>& out_pts) +{ + for (size_t ki=0; ki<points.size(); ++ki) + { + if (distang[ki].first <= lim) + in_pts.push_back(points[ki]); + else + out_pts.push_back(points[ki]); + } +} + +shared_ptr<ElementarySurface> +RevEng::defineElemSurf(vector<RevEngPoint*>& points, + vector<RevEngPoint*>& in_points, + BoundingBox& bbox, vector<RevEngPoint*>& remain) +//=========================================================================== +{ + shared_ptr<ElementarySurface> dummy_sf; + + // Collect direction information in adjacent surfaces + vector<pair<RevEngRegion*,int> > adj_sf_regs; + collectAdjacentSurfRegs(points, adj_sf_regs); + + vector<Point> vecs1; + vector<int> num_reg_pts; + for (size_t ki=0; ki<adj_sf_regs.size(); ++ki) + { + shared_ptr<ParamSurface> surf = + adj_sf_regs[ki].first->getSurface(0)->surface(); + shared_ptr<ElementarySurface> elem = + dynamic_pointer_cast<ElementarySurface,ParamSurface>(surf); + if (!elem.get()) + continue; + vecs1.push_back(elem->direction()); + num_reg_pts.push_back(adj_sf_regs[ki].first->numPoints()); + } + + vector<Point> vecs2(model_axis_.size()); + vector<int> num_axis_pt(model_axis_.size(), 0); + for (size_t ki=0; ki<model_axis_.size(); ++ki) + { + vecs2[ki] = model_axis_[ki].axis_; + for (size_t kj=0; kj<model_axis_[ki].plane_loc_.size(); ++kj) + num_axis_pt[ki] += model_axis_[ki].plane_loc_[kj].second; + for (size_t kj=0; kj<model_axis_[ki].rotational_loc_.size(); ++kj) + num_axis_pt[ki] += model_axis_[ki].rotational_loc_[kj].second; + } + + // Prepare points for surface generation + vector<RevEngPoint*> dummy_pts; + vector<pair<vector<RevEngPoint*>::iterator,vector<RevEngPoint*>::iterator> > pts_it; + pts_it.push_back(std::make_pair(points.begin(), points.end())); + vector<Point> pts(points.size()); + bbox = BoundingBox(3); + for (size_t ki=0; ki<points.size(); ++ki) + { + Vector3D xyz = points[ki]->getPoint(); + pts[ki] = Point(xyz[0], xyz[1], xyz[2]); + bbox.addUnionWith(pts[ki]); + } + Point low = bbox.low(); + Point high = bbox.high(); + +#ifdef DEBUG_SMALL + std::ofstream of("remaining_group.g2"); + of << "400 1 0 4 55 100 100 255" << std::endl; + of << points.size() << std::endl; + for (size_t ki=0; ki<points.size(); ++ki) + of << points[ki]->getPoint() << std::endl; +#endif + // Collect information about feasible approximating surfaces + double eps = 1.0e-9; + double angtol = 5.0*anglim_; + double tol2 = 2.0*approx_tol_; + double avd_fac = 2.0; + double in_fac = 0.2; + double fac1 = 0.9; + double fac2 = 0.9; + double red_fac = 0.75; + double ang_lim2 = 0.25*M_PI; + + vector<shared_ptr<ElementarySurface> > elem_sfs; + vector<int> flag; + vector<FittingResults> acc_fit; + vector<vector<RevEngPoint*> > used_pts; + vector<vector<RevEngPoint*> > not_used_pts; + + // Plane + Point init_norm = points[0]->getTriangNormal(); + Point pos1, norm1, Cx1, Cy1; + RevEngUtils::computePlane(pts, init_norm, mainaxis_, pos1, norm1, Cx1, Cy1); + if (norm1.length() < 0.1) + return dummy_sf; // The length should be one, but could be zero if the + // approximation fails + shared_ptr<Plane> plane1(new Plane(pos1, norm1, Cx1)); + +#ifdef DEBUG_SMALL + plane1->writeStandardHeader(of); + plane1->write(of); +#endif + FittingResults acc1; + RevEngUtils::distToSurf(points.begin(), points.end(), plane1, approx_tol_, + acc1.maxd, acc1.avd, acc1.inside, acc1.inside_2, + acc1.param, acc1.distang, angtol); + if (acc1.avd < avd_fac*approx_tol_ && (double)acc1.inside_2 > in_fac*(double)points.size()) + { + int surf_flag1 = regions_[0]->defineSfFlag((int)points.size(), 0, approx_tol_, + acc1.inside, acc1.inside_2, + acc1.avd, false); + // Possible surface. Check with alternative plane normal + Point dir; + double ang = mostCompatibleDir(plane1->direction(), vecs1, vecs2, dir); + if (ang > eps && ang <= angtol) + { + // Update plane with new normal + shared_ptr<Plane> plane2 = + RevEngUtils::planeWithAxis(points, dir, plane1->location(), mainaxis_); + FittingResults acc2; + RevEngUtils::distToSurf(points.begin(), points.end(), plane1, approx_tol_, + acc2.maxd, acc2.avd, acc2.inside, acc2.inside_2, + acc2.param, acc2.distang, angtol); + int surf_flag2 = regions_[0]->defineSfFlag((int)points.size(), 0, approx_tol_, + acc2.inside, acc2.inside_2, + acc2.avd, false); + if (surf_flag2 <= surf_flag1 && acc2.avd <= fac1*acc1.avd && + (double)acc2.inside_2 >= fac2*(double)acc1.inside_2) + { +#ifdef DEBUG_SMALL + plane2->writeStandardHeader(of); + plane2->write(of); +#endif + std::swap(acc1, acc2); + std::swap(plane1, plane2); + } + } + + bool use_reduced = false; + if (acc1.maxd > tol2) + { + // Remove most distant points and make a refit + vector<RevEngPoint*> in_pts, out_pts; + identifyDistPoints(points, acc1.distang, tol2, in_pts, out_pts); + if ((double)in_pts.size() > red_fac*(double)points.size()) + { + vector<Point> in_pts2(in_pts.size()); + for (size_t ki=0; ki<in_pts.size(); ++ki) + { + Vector3D xyz = in_pts[ki]->getPoint(); + in_pts2[ki] = Point(xyz[0], xyz[1], xyz[2]); + } + Point pos2, norm2, Cx2, Cy2; + RevEngUtils::computePlane(in_pts2, plane1->direction(), mainaxis_, pos2, + norm2, Cx2, Cy2); + shared_ptr<Plane> plane2(new Plane(pos2, norm2, Cx2)); + + FittingResults acc2; + RevEngUtils::distToSurf(in_pts.begin(), in_pts.end(), plane2, approx_tol_, + acc2.maxd, acc2.avd, acc2.inside, acc2.inside_2, + acc2.param, acc2.distang, angtol); + int surf_flag2 = regions_[0]->defineSfFlag((int)in_pts.size(), 0, approx_tol_, + acc2.inside, acc2.inside_2, + acc2.avd, false); + double frac1 = (double)acc1.inside_2/(double)points.size(); + double frac2 = (double)acc2.inside_2/(double)in_pts.size(); + if (surf_flag2 < ACCURACY_POOR && + surf_flag2 <= surf_flag1 && acc2.avd < acc1.avd && frac2 > frac1) + { +#ifdef DEBUG_SMALL + plane2->writeStandardHeader(of); + plane2->write(of); +#endif + use_reduced = true; + elem_sfs.push_back(plane2); + flag.push_back(surf_flag2); + acc_fit.push_back(acc2); + used_pts.push_back(in_pts); + not_used_pts.push_back(out_pts); + } + } + } + if (surf_flag1 < ACCURACY_POOR && (!use_reduced)) + { + elem_sfs.push_back(plane1); + flag.push_back(surf_flag1); + acc_fit.push_back(acc1); + used_pts.push_back(points); + not_used_pts.push_back(dummy_pts); + } + } + + // Cylinder and cone + Point axis2, Cx2, Cy2, pos2; + double rad2; + RevEngUtils::computeAxis(pts_it, axis2, Cx2, Cy2); + RevEngUtils::computeCylPosRadius(pts_it, low, high, axis2, Cx2, Cy2, pos2, rad2); + shared_ptr<ElementarySurface> csf1(new Cylinder(rad2, pos2, axis2, Cx2)); +#ifdef DEBUG_SMALL + csf1->writeStandardHeader(of); + csf1->write(of); +#endif + + FittingResults acc2; + RevEngUtils::distToSurf(points.begin(), points.end(), csf1, approx_tol_, + acc2.maxd, acc2.avd, acc2.inside, acc2.inside_2, + acc2.param, acc2.distang, angtol); + + shared_ptr<Cone> cone = + RevEngUtils::coneWithAxis(points, csf1->direction(), low, high, mainaxis_); + if (fabs(cone->getConeAngle()) > angtol) + { + FittingResults acc3; + RevEngUtils::distToSurf(points.begin(), points.end(), cone, approx_tol_, + acc3.maxd, acc3.avd, acc3.inside, acc3.inside_2, + acc3.param, acc3.distang, angtol); + if (acc3.avd < acc2.avd && acc3.inside_2 > acc2.inside_2) + { +#ifdef DEBUG_SMALL + cone->writeStandardHeader(of); + cone->write(of); +#endif + std::swap(acc2, acc3); + csf1 = cone; + } + } + + if (acc2.avd < avd_fac*approx_tol_ && (double)acc2.inside_2 > in_fac*(double)points.size()) + { + int surf_flag2 = regions_[0]->defineSfFlag((int)points.size(), 0, approx_tol_, + acc2.inside, acc2.inside_2, + acc2.avd, true); + + // Possible surface. Check with alternative plane normal + Point dir; + double ang = mostCompatibleDir(csf1->direction(), vecs1, vecs2, dir); + if (ang > eps && ang < ang_lim2) + { + // Update rotational surface with new axis + shared_ptr<ElementarySurface> csf2 = + RevEngUtils::cylinderWithAxis(points, dir, low, high, mainaxis_); + + FittingResults acc3; + RevEngUtils::distToSurf(points.begin(), points.end(), csf2, approx_tol_, + acc3.maxd, acc3.avd, acc3.inside, acc3.inside_2, + acc3.param, acc3.distang, angtol); + + shared_ptr<Cone> cone2 = + RevEngUtils::coneWithAxis(points, csf2->direction(), low, high, mainaxis_); + if (fabs(cone2->getConeAngle()) > angtol) + { + FittingResults acc4; + RevEngUtils::distToSurf(points.begin(), points.end(), cone, approx_tol_, + acc4.maxd, acc4.avd, acc4.inside, acc4.inside_2, + acc4.param, acc4.distang, angtol); + if (acc4.avd < acc3.avd && acc4.inside_2 > acc3.inside_2) + { + std::swap(acc3, acc4); + csf2 = cone2; + } + } + + int surf_flag3 = regions_[0]->defineSfFlag((int)points.size(), 0, approx_tol_, + acc3.inside, acc3.inside_2, + acc3.avd, true); + if (surf_flag3 <= surf_flag2 && acc3.avd <= fac1*acc2.avd && + (double)acc3.inside_2 >= fac2*(double)acc2.inside_2) + { +#ifdef DEBUG_SMALL + csf2->writeStandardHeader(of); + csf2->write(of); +#endif + std::swap(acc2, acc3); + std::swap(csf1, csf2); + } + } + + bool use_reduced = false; + if (acc2.maxd > tol2) + { + // Remove most distant points and make a refit + vector<RevEngPoint*> in_pts, out_pts; + identifyDistPoints(points, acc2.distang, tol2, in_pts, out_pts); + if ((double)in_pts.size() > red_fac*(double)points.size()) + { + vector<pair<vector<RevEngPoint*>::iterator,vector<RevEngPoint*>::iterator> > pts_it2; + pts_it2.push_back(std::make_pair(in_pts.begin(), in_pts.end())); + Point axis3, Cx3, Cy3, pos3; + double rad3; + RevEngUtils::computeAxis(pts_it2, axis3, Cx3, Cy3); + RevEngUtils::computeCylPosRadius(pts_it2, low, high, axis3, Cx3, Cy3, + pos3, rad3); + shared_ptr<ElementarySurface> csf2(new Cylinder(rad3, pos3, axis3, Cx3)); + + + FittingResults acc3; + RevEngUtils::distToSurf(in_pts.begin(), in_pts.end(), csf2, approx_tol_, + acc3.maxd, acc3.avd, acc3.inside, acc3.inside_2, + acc3.param, acc3.distang, angtol); + shared_ptr<Cone> cone2 = + RevEngUtils::coneWithAxis(in_pts, csf2->direction(), low, high, mainaxis_); + if (fabs(cone2->getConeAngle()) > angtol) + { + FittingResults acc4; + RevEngUtils::distToSurf(in_pts.begin(), in_pts.end(), cone2, approx_tol_, + acc4.maxd, acc4.avd, acc4.inside, acc4.inside_2, + acc4.param, acc4.distang, angtol); + if (acc4.avd < acc3.avd && acc4.inside_2 > acc3.inside_2) + { + std::swap(acc3, acc4); + csf2 = cone2; + } + } + + int surf_flag3 = regions_[0]->defineSfFlag((int)in_pts.size(), 0, approx_tol_, + acc3.inside, acc3.inside_2, + acc3.avd, true); + double frac1 = (double)acc2.inside_2/(double)points.size(); + double frac2 = (double)acc3.inside_2/(double)in_pts.size(); + if (surf_flag3 < ACCURACY_POOR && + surf_flag3 <= surf_flag2 && acc3.avd < acc2.avd && frac2 > frac1) + { +#ifdef DEBUG_SMALL + csf2->writeStandardHeader(of); + csf2->write(of); +#endif + use_reduced = true; + elem_sfs.push_back(csf2); + flag.push_back(surf_flag3); + acc_fit.push_back(acc3); + used_pts.push_back(in_pts); + not_used_pts.push_back(out_pts); + } + } + } + if (surf_flag2 < ACCURACY_POOR && (!use_reduced)) + { + elem_sfs.push_back(csf1); + flag.push_back(surf_flag2); + acc_fit.push_back(acc2); + used_pts.push_back(points); + not_used_pts.push_back(dummy_pts); + } + } + + // Sphere + int ix = 0; + for (size_t ki=1; ki<num_axis_pt.size(); ++ki) + if (num_axis_pt[ki] > num_axis_pt[ix]) + ix = (int)ki; + Point axis3 = vecs2[ix]; + + shared_ptr<Sphere> sph1 = RevEngUtils::sphereWithAxis(points, axis3, mainaxis_); + FittingResults acc3; + RevEngUtils::distToSurf(points.begin(), points.end(), sph1, approx_tol_, + acc3.maxd, acc3.avd, acc3.inside, acc3.inside_2, + acc3.param, acc3.distang, angtol); + +#ifdef DEBUG_SMALL + sph1->writeStandardHeader(of); + sph1->write(of); +#endif + if (acc3.avd < avd_fac*approx_tol_ && (double)acc3.inside_2 > in_fac*(double)points.size()) + { + int surf_flag3 = regions_[0]->defineSfFlag((int)points.size(), 0, approx_tol_, + acc3.inside, acc3.inside_2, + acc3.avd, false); + bool use_reduced = false; + if (acc3.maxd > tol2) + { + // Remove most distant points and make a refit + vector<RevEngPoint*> in_pts, out_pts; + identifyDistPoints(points, acc3.distang, tol2, in_pts, out_pts); + if ((double)in_pts.size() > red_fac*(double)points.size()) + { + shared_ptr<Sphere> sph2 = RevEngUtils::sphereWithAxis(in_pts, axis3, mainaxis_); + FittingResults acc4; + RevEngUtils::distToSurf(in_pts.begin(), in_pts.end(), sph2, approx_tol_, + acc4.maxd, acc4.avd, acc4.inside, acc4.inside_2, + acc4.param, acc4.distang, angtol); + int surf_flag4 = regions_[0]->defineSfFlag((int)in_pts.size(), 0, approx_tol_, + acc3.inside, acc3.inside_2, + acc3.avd, false); + double frac1 = (double)acc3.inside_2/(double)points.size(); + double frac2 = (double)acc4.inside_2/(double)in_pts.size(); + if (surf_flag4 < ACCURACY_POOR && + surf_flag4 <= surf_flag3 && acc4.avd < acc3.avd && frac2 > frac1) + { +#ifdef DEBUG_SMALL + sph2->writeStandardHeader(of); + sph2->write(of); +#endif + use_reduced = true; + elem_sfs.push_back(sph2); + flag.push_back(surf_flag4); + acc_fit.push_back(acc4); + used_pts.push_back(in_pts); + not_used_pts.push_back(out_pts); + } + } + } + if (surf_flag3 < ACCURACY_POOR && (!use_reduced)) + { + elem_sfs.push_back(sph1); + flag.push_back(surf_flag3); + acc_fit.push_back(acc3); + used_pts.push_back(points); + not_used_pts.push_back(dummy_pts); + } + } + + // Select result + ix = -1; + int sf_flag = NOT_SET; + double inside_fac = 0.1; + for (size_t ki=0; ki<elem_sfs.size(); ++ki) + { + if ((double)acc_fit[ki].inside < inside_fac*(double)used_pts[ki].size()) + continue; + if (flag[ki] < sf_flag) + { + ix = (int)ki; + sf_flag = flag[ki]; + } + else if ((flag[ki] == sf_flag || + (std::min(flag[ki],sf_flag) == 1 && std::max(flag[ki],sf_flag) == 2)) && + acc_fit[ki].avd < acc_fit[ix].avd && + acc_fit[ki].inside_2 > acc_fit[ix].inside_2) + { + ix = (int)ki; + sf_flag = flag[ki]; + } + } + + if (ix >= 0) + { + in_points = used_pts[ix]; + remain = not_used_pts[ix]; + return elem_sfs[ix]; + } + else + return dummy_sf; +} + +//=========================================================================== +void RevEng::planarAtPlane(shared_ptr<Plane> axis_plane, + vector<RevEngPoint*>& points, + vector<HedgeSurface*>& sfs, + vector<shared_ptr<RevEngRegion> >& plane_sf_reg, + vector<shared_ptr<HedgeSurface> >& plane_sf_hedge) +//=========================================================================== +{ + if (sfs.size() == 0 || points.size() == 0) + return; + + RevEngRegion *reg0 = sfs[0]->getRegion(0); + Point axis = axis_plane->direction(); + Point loc = axis_plane->location(); + int min_num_pts = min_point_region_/5; + double int_tol = 1.0e-4; + + // Check accuracy with respect to axis plane + double angtol = 5.0*anglim_; + double maxdist, avdist; + int num_in, num2_in; + vector<double> parvals; + vector<pair<double,double> > distang; + vector<RevEngPoint*> in, out; + RevEngUtils::distToSurf(points.begin(), points.end(), axis_plane, approx_tol_, + maxdist, avdist, num_in, num2_in, in, out, + parvals, distang, angtol); + int sf_flag = reg0->defineSfFlag((int)points.size(), 0, approx_tol_, num_in, + num2_in, avdist, false); + + vector<bool> same_plane(sfs.size(), true); + double dtol = std::min(1.0e-4, 0.1*approx_tol_); + double atol = 0.001; + for (size_t ki=0; ki<sfs.size(); ++ki) + { + shared_ptr<ParamSurface> surf = sfs[ki]->surface(); + shared_ptr<Plane> plane = dynamic_pointer_cast<Plane,ParamSurface>(surf); + if (!plane.get()) + continue; + double ang = plane->direction().angle(axis); + ang = std::min(ang, M_PI-ang); + double dd = (plane->location() - loc)*axis; + if (ang > atol || dd > dtol) + same_plane[ki] = false; + } + + // Check accuracy with respect to existing planar surfaces + vector<int> flag_sfs(sfs.size(), sf_flag); + vector<int> flag_axis(sfs.size(), NOT_SET); + vector<bool> has_revedgs(sfs.size(), false); + vector<int> num_points(sfs.size()); + vector<RevEngRegion*> sfs_reg(sfs.size()); + for (size_t ki=0; ki<sfs.size(); ++ki) + { + RevEngRegion *reg = sfs[ki]->getRegion(0); + sfs_reg[ki] = reg; + num_points[ki] = reg->numPoints(); + has_revedgs[ki] = reg->hasRevEdges(); + if (same_plane[ki]) + { + flag_axis[ki] = reg->getSurfaceFlag(); + continue; + } + + shared_ptr<ParamSurface> surf = sfs[ki]->surface(); + shared_ptr<Plane> plane = dynamic_pointer_cast<Plane,ParamSurface>(surf); + if (!plane.get()) + continue; + // To avoid bounded plane + shared_ptr<Plane> plane2(new Plane(plane->location(), plane->direction())); + double maxd, avd; + int inside, inside2; + vector<double> param; + vector<pair<double,double> > d_a; + vector<RevEngPoint*> in0, out0; + RevEngUtils::distToSurf(points.begin(), points.end(), plane2, approx_tol_, + maxd, avd, inside, inside2, in0, out0, + param, d_a, angtol); + flag_sfs[ki] = reg0->defineSfFlag((int)points.size(), 0, approx_tol_, inside, + inside2, avd, false); + if (sf_flag >= ACCURACY_POOR && flag_sfs[ki] >= ACCURACY_POOR) + continue; // Not compatible + + if (sf_flag < ACCURACY_POOR) + { + double maxd2, avd2; + int inside_2, inside2_2; + vector<double> param2; + vector<pair<double,double> > d_a2; + vector<RevEngPoint*> in2, out2; + RevEngUtils::distToSurf(reg->pointsBegin(), reg->pointsEnd(), axis_plane, + approx_tol_, maxd2, avd2, inside_2, inside2_2, in2, out2, + param2, d_a2, angtol); + flag_axis[ki] = reg->defineSfFlag(0, approx_tol_, inside_2, + inside2_2, avd2, false); + int stop_break = 1; + } + int stop_break2 = 1; + } + + // Check if the planar points can be integrated in any of the existing surfaces + int ix = -1; + for (size_t ki=0; ki<sfs.size(); ++ki) + { + if (flag_sfs[ki] < ACCURACY_POOR && + (ix < 0 || flag_sfs[ki] < flag_sfs[ix] || + (flag_sfs[ki] == flag_sfs[ix] && has_revedgs[ki] && (!has_revedgs[ix])) || + (flag_sfs[ki] == flag_sfs[ix] && has_revedgs[ki] == has_revedgs[ix] && + num_points[ki] > num_points[ix]))) + ix = ki; + } + + if (ix < 0 && (sf_flag >= ACCURACY_POOR || (int)points.size() < min_num_pts)) + return; + + // Collect all points and parameterize on selected surface + shared_ptr<ParamSurface> sel_sf = (ix < 0) ? axis_plane : sfs[ix]->surface(); + vector<RevEngPoint*> all_pts; + for (size_t ki=0; ki<sfs.size(); ++ki) + if (flag_axis[ki] < ACCURACY_POOR) + all_pts.insert(all_pts.end(), sfs_reg[ki]->pointsBegin(), + sfs_reg[ki]->pointsEnd()); + all_pts.insert(all_pts.end(), points.begin(), points.end()); + double maxd_all, avd_all; + int num_in_all, num2_in_all; + vector<double> parvals_all; + vector<pair<double,double> > distang_all; + vector<RevEngPoint*> in_all, out_all; + RevEngUtils::distToSurf(all_pts.begin(), all_pts.end(), sel_sf, approx_tol_, + maxd_all, avd_all, num_in_all, num2_in_all, in_all, + out_all, parvals_all, distang_all, angtol); + int sf_flag_all = reg0->defineSfFlag((int)all_pts.size(), 0, approx_tol_, + num_in_all, num2_in_all, avd_all, false); + if (sf_flag_all >= ACCURACY_POOR) + return; // Do nothing + + // Assign parameter value and accuracy to points. This might have to be redone + for (size_t ki=0; ki<all_pts.size(); ++ki) + { + all_pts[ki]->setPar(Vector2D(parvals_all[2*ki], parvals_all[2*ki+1])); + all_pts[ki]->setSurfaceDist(distang_all[ki].first, distang_all[ki].second); + } + + vector<vector<RevEngPoint*> > con_all; + RevEngUtils::identifyConGroups(all_pts, con_all); +#ifdef DEBUG_SMALL + std::ofstream of1("sep_pts_all.g2"); + for (size_t ki=0; ki<con_all.size(); ++ki) + { + of1 << "400 1 0 0" << std::endl; + of1 << con_all[ki].size() << std::endl; + for (size_t kj=0; kj<con_all[ki].size(); ++kj) + of1 << con_all[ki][kj]->getPoint() << std::endl; + } +#endif + + for (size_t ki=0; ki<con_all.size(); ++ki) + { + // Assemble accuracy information + double maxdc = 0.0, avdc = 0.0; + int num_inc = 0, num2_inc = 0, ang_in = 0; + double fac = 1.0/(double)con_all[ki].size(); + for (size_t kj=0; kj<con_all[ki].size(); ++kj) + { + double dd, ang; + con_all[ki][kj]->getSurfaceDist(dd, ang); + maxdc = std::max(maxdc, dd); + avdc += fac*dd; + if (dd <= approx_tol_ && ang <= angtol) + num_inc++; + if (dd <= approx_tol_) + num2_inc++; + if (ang <= angtol) + ang_in++; + } + int flagc = reg0->defineSfFlag((int)con_all[ki].size(), 0, approx_tol_, + num_inc, num2_inc, avdc, false); + int min_nmb = std::max((int)con_all[ki].size()/4, 10); + if (ang_in < min_nmb && num_inc < min_nmb) + flagc = ACCURACY_POOR; + if (flagc < ACCURACY_POOR && (int)con_all[ki].size() > min_num_pts/2) + { + // Check connection to existing surface + vector<int> num_sf_points(sfs.size(), 0); + for (size_t kj=0; kj<con_all[ki].size(); ++kj) + { + RevEngRegion *curr_reg = con_all[ki][kj]->region(); + for (size_t kr=0; kr<sfs.size(); ++kr) + if (curr_reg == sfs_reg[kr]) + { + num_sf_points[kr]++; + break; + } + } + + // Decide on corresponding surface + int ix2 = -1; + int num_corr = 0; + for (size_t kr=0; kr<num_sf_points.size(); ++kr) + if (num_sf_points[kr] > num_corr) + { + ix2 = (int)kr; + num_corr = num_sf_points[kr]; + } + + // Remove the associated points from their previous region + // Collect points with respect to regions + vector<vector<RevEngPoint*> > reg_points; + for (size_t kj=0; kj<con_all[ki].size(); ++kj) + { + RevEngRegion *curreg = con_all[ki][kj]->region(); + if ((ix2 >=0 && curreg != sfs_reg[ix2]) || ix2 < 0) + { + size_t kr; + for (kr=0; kr<reg_points.size(); ++kr) + if (reg_points[kr][0]->region() == curreg) + break; + if (kr < reg_points.size()) + reg_points[kr].push_back(con_all[ki][kj]); + else + { + vector<RevEngPoint*> curr_reg_pt; + curr_reg_pt.push_back(con_all[ki][kj]); + reg_points.push_back(curr_reg_pt); + } + } + } + for (size_t kr=0; kr<reg_points.size(); ++kr) + { + RevEngRegion *currreg = reg_points[kr][0]->region(); + currreg->removePoints(reg_points[kr]); + for (size_t kh=0; kh<reg_points[kr].size(); ++kh) + reg_points[kr][kh]->unsetRegion(); + } + + if (ix2 < 0) + { + // Define new region and surface + shared_ptr<RevEngRegion> plane_reg(new RevEngRegion(reg0->getClassificationType(), + edge_class_type_, + con_all[ki])); + shared_ptr<Plane> plane2(axis_plane->clone()); + shared_ptr<HedgeSurface> hedge(new HedgeSurface(sel_sf, plane_reg.get())); + plane_reg->setHedge(hedge.get()); + plane_reg->updateInfo(approx_tol_, angtol); + plane_reg->setSurfaceFlag(flagc); + plane_sf_reg.push_back(plane_reg); + plane_sf_hedge.push_back(hedge); + } + else + { + // Enhance region with added points + vector<RevEngPoint*> added_pts; + for (size_t kj=0; kj<con_all[ki].size(); ++kj) + { + if (con_all[ki][kj]->region() != sfs_reg[ix2]) + added_pts.push_back(con_all[ki][kj]); + } + if (added_pts.size() > 0) + { + sfs_reg[ix2]->addPointsToGroup(added_pts, approx_tol_, angtol, false); + vector<RevEngEdge*> rev_edgs = sfs_reg[ix2]->getAllRevEdges(); + for (size_t kj=0; kj<rev_edgs.size(); ++kj) + rev_edgs[kj]->increaseExtendCount(); + } + if (ix2 != ix) + { + // Reset parameterization + sfs_reg[ix2]->parameterizePoints(approx_tol_, angtol); + } + } + int stop_break5 = 1; + } + else + { + // Reset current parameterization, if any + double eps = 1.0e-6; + double upar, vpar, dist; + Point close; + Point norm1, norm2, norm3; + double ang, ang2; + for (size_t kj=0; kj<con_all[ki].size(); ++kj) + { + RevEngPoint *currpt = con_all[ki][kj]; + RevEngRegion *curreg = currpt->region(); + if (curreg->hasSurface()) + { + shared_ptr<ParamSurface> surf = curreg->getSurface(0)->surface(); + Vector3D xyz = currpt->getPoint(); + Point pnt(xyz[0], xyz[1], xyz[2]); + surf->closestPoint(pnt, upar, vpar, close, dist, eps); + surf->normal(norm1, upar, vpar); + norm2 = currpt->getLocFuncNormal(); + norm3 = currpt->getTriangNormal(); + ang = norm1.angle(norm2); + ang2 = norm1.angle(norm3); + ang = std::min(std::min(M_PI-ang, ang), std::min(M_PI-ang2,ang2)); + currpt->setPar(Vector2D(upar, vpar)); + currpt->setSurfaceDist(dist, ang); + } + } + } + int stop_break4 = 1; + } + + vector<vector<RevEngPoint*> > separate_groups; + vector<HedgeSurface*> removed_surfs; + vector<RevEngEdge*> removed_edgs; + for (size_t ki=0; ki<sfs_reg.size(); ++ki) + { + if (sfs_reg[ki]->numPoints() == 0) + { + vector<RevEngEdge*> rev_edgs = sfs_reg[ki]->getAllRevEdges(); + for (size_t kr=0; kr<rev_edgs.size(); ++kr) + { + size_t kj; + for (kj=0; kj<edges_.size(); ++kj) + if (edges_[kj].get() == rev_edgs[kr]) + break; + if (kj < edges_.size()) + edges_.erase(edges_.begin()+kj); + } + + // Remove from region pool + for (size_t kr=0; kr<regions_.size(); ++kr) + if (regions_[kr].get() == sfs_reg[ki]) + { + regions_[kr]->removeFromAdjacent(); + regions_[kr]->clearRegionAdjacency(); + regions_.erase(regions_.begin()+kr); + break; + } + removed_surfs.push_back(sfs[ki]); + sfs[ki] = 0; + } + else + { + // Split region if not connected + sfs_reg[ki]->splitRegion(separate_groups); + if (sfs_reg[ki]->numPoints() < min_num_pts) + { + vector<RevEngEdge*> rev_edgs = sfs_reg[ki]->getAllRevEdges(); + if (rev_edgs.size() > 0) + removed_edgs.insert(removed_edgs.end(), rev_edgs.begin(), rev_edgs.end()); + removed_surfs.push_back(sfs_reg[ki]->getSurface(0)); + sfs_reg[ki]->clearSurface(); + } + } + } + surfaceExtractOutput(-1, separate_groups, removed_surfs); + for (size_t ki=0; ki<removed_edgs.size(); ++ki) + { + size_t kj; + for (kj=0; kj<edges_.size(); ++kj) + if (edges_[kj].get() == removed_edgs[ki]) + break; + if (kj < edges_.size()) + edges_.erase(edges_.begin()+kj); + } + + + int stop_break3 = 1; +} + +//=========================================================================== +void RevEng::integrateInSmallSurfs(vector<shared_ptr<RevEngRegion> >& small_sf_reg, + vector<RevEngRegion*>& nosf_reg, + vector<RevEngRegion*>& include_reg) +//=========================================================================== +{ + // Sort small regions according to size (could possibly include also accuracy) + for (size_t ki=0; ki<small_sf_reg.size(); ++ki) + for (size_t kj=ki+1; kj<small_sf_reg.size(); ++kj) + if (small_sf_reg[kj]->numPoints() > small_sf_reg[ki]->numPoints()) + std::swap(small_sf_reg[ki], small_sf_reg[kj]); + + // Check accuracy of not assigned regions with respect to the small surfaces + double angtol = 5.0*anglim_; + for (size_t ki=0; ki<nosf_reg.size(); ++ki) + { + BoundingBox bb1 = nosf_reg[ki]->getBbox(); + vector<double> maxdist, avdist; + vector<int> num_in, num2_in; + vector<vector<double> > parvals; + vector<vector<pair<double,double> > > distang; + vector<int> sfflag; + vector<size_t> cand_ix; + for (size_t kj=0; kj<small_sf_reg.size(); ++kj) + { + BoundingBox bb2 = small_sf_reg[kj]->getBbox(); + if (!bb1.overlaps(bb2, approx_tol_)) + continue; + shared_ptr<ParamSurface> surf = small_sf_reg[kj]->getSurface(0)->surface(); + bool cyllike = (surf->instanceType() == Class_Cylinder || + surf->instanceType() == Class_Cone); + double maxd, avd; + int inside, inside2; + vector<double> param; + vector<pair<double,double> > d_a; + vector<RevEngPoint*> in, out; + RevEngUtils::distToSurf(nosf_reg[ki]->pointsBegin(), + nosf_reg[ki]->pointsEnd(), surf, approx_tol_, + maxd, avd, inside, inside2, in, out, + param, d_a, angtol); + int sf_flag = small_sf_reg[kj]->defineSfFlag(0, approx_tol_, inside, + inside2, avd, cyllike); + if (sf_flag < ACCURACY_POOR) + { + // Check "closeness" + double dom1[4]; + small_sf_reg[kj]->getDomain(dom1); + RectDomain sf_dom(Vector2D(dom1[0],dom1[2]), Vector2D(dom1[1],dom1[3])); + Vector2D c1(param[0], param[1]); + Vector2D c2(param[0], param[1]); + for (size_t kr=2; kr<param.size(); kr+=2) + { + c1[0] = std::min(c1[0], param[kr]); + c2[0] = std::max(c2[0], param[kr]); + c1[1] = std::min(c1[1], param[kr+1]); + c2[1] = std::max(c2[1], param[kr+1]); + } + RectDomain pnt_dom(c1, c2); + double udel = 0.25*(dom1[1]-dom1[0]); + double vdel = 0.25*(dom1[3]-dom1[2]); + BoundingBox bb1 = small_sf_reg[kj]->boundingBox(); + double ddel = 0.25*bb1.low().dist(bb1.high()); + BoundingBox bb2 = nosf_reg[ki]->boundingBox(); + if (sf_dom.overlap(pnt_dom, udel, vdel) && + bb1.overlaps(bb2, ddel)) + { + maxdist.push_back(maxd); + avdist.push_back(avd); + num_in.push_back(inside); + num2_in.push_back(inside2); + parvals.push_back(param); + distang.push_back(d_a); + sfflag.push_back(sf_flag); + cand_ix.push_back(kj); + } + } + } + if (cand_ix.size() > 0) + { + // Sort candidates + double eps = 0.01*approx_tol_; + vector<int> perm(cand_ix.size()); + for (size_t kj=0; kj<perm.size(); ++kj) + perm[kj] = kj; + for (size_t kj=0; kj<perm.size(); ++kj) + for (size_t kr=kj+1; kr<perm.size(); ++kr) + if (sfflag[perm[kr]] < sfflag[perm[kj]] || + (sfflag[perm[kr]] == sfflag[perm[kj]] && + avdist[perm[kr]] < avdist[perm[kj]]-eps)) + std::swap(perm[kj], perm[kr]); + + vector<RevEngRegion*> dummy; + small_sf_reg[cand_ix[perm[0]]]->includeAdjacentRegion(nosf_reg[ki], + maxdist[perm[0]], + avdist[perm[0]], + num_in[perm[0]], + num2_in[perm[0]], + parvals[perm[0]], + distang[perm[0]], + dummy); + include_reg.push_back(nosf_reg[ki]); + } + + int stop_break1 = 1; + } + int stop_break2 = 1; +} + +bool checkAccuracy(RevEngRegion* reg, int min_num_pt, double tol, double angtol, + shared_ptr<ElementarySurface> surf, + vector<vector<RevEngPoint*> >& points, vector<BoundingBox>& bb, + size_t& num_points, double& maxdist, double& avdist, int& num_in, + int& num2_in, vector<vector<double> >& parvals, + vector<vector<pair<double,double> > >& dist_ang, + vector<RevEngPoint*>& non_assigned_pts) +{ + num_points = 0; + maxdist = 0.0; + avdist = 0.0; + num_in = 0; + num2_in = 0; + bool type_cyl = (surf->instanceType() == Class_Cylinder || + surf->instanceType() == Class_Cone); + for (size_t kj=0; kj<points.size(); ) + { + if (points[kj].size() == 0) + { + points.erase(points.begin()+kj); + continue; + } + double maxd, avd; + int inside, inside2; + vector<double> param; + vector<pair<double,double> > d_a; + vector<RevEngPoint*> in, out; + RevEngUtils::distToSurf(points[kj].begin(), points[kj].end(), + surf, tol, maxd, avd, inside, + inside2, in, out, param, d_a, angtol); + int sf_flag = reg->defineSfFlag((int)points[kj].size(), 0, + tol, inside, inside2, avd, type_cyl); + if (sf_flag >= ACCURACY_POOR) + { + non_assigned_pts.insert(non_assigned_pts.end(), points[kj].begin(), + points[kj].end()); + points.erase(points.begin()+kj); + bb.erase(bb.begin()+kj); + } + else + { + maxdist = std::max(maxdist, maxd); + avdist += avd; + num_in += inside; + num2_in += inside2; + parvals.push_back(param); + dist_ang.push_back(d_a); + num_points += points[kj].size(); + ++kj; + } + } + avdist /= (double)parvals.size(); + if ((int)num_points < min_num_pt) + { + for (size_t kj=0; kj<points.size(); ++kj) + if (points[kj].size() > 0) + non_assigned_pts.insert(non_assigned_pts.end(), points[kj].begin(), + points[kj].end()); + return false; + } + return true; +} + +//=========================================================================== +void RevEng::extractSmallSurfs(SmallSurface& small_surf, + vector<shared_ptr<RevEngRegion> >& small_sf_reg, + vector<shared_ptr<HedgeSurface> >& small_sf_hedge, + vector<RevEngRegion*>& nosf_reg, + vector<RevEngPoint*>& non_assigned_pts) +//=========================================================================== +{ + double eps = 1.0e-6; + double angtol = 5.0*anglim_; + int min_num_pt = min_point_region_/10; + int classtype = CLASSIFICATION_UNDEF; + + vector<shared_ptr<ElementarySurface> > surfs = small_surf.surfs_; + vector<vector<vector<RevEngPoint*> > > points(surfs.size()); + vector<vector<BoundingBox> > bb(surfs.size()); + if (surfs.size() == 1) + { + points[0] = small_surf.assos_points_; + bb[0] = small_surf.bbox_; + } + else + { + // Distribute points according to surfaces + for (size_t ki=0; ki<surfs.size(); ++ki) + { + points[ki].resize(small_surf.assos_points_.size()); + bb[ki].resize(small_surf.assos_points_.size()); + for (size_t kr=0; kr<bb[ki].size(); ++kr) + bb[ki][kr] = BoundingBox(3); + } + + for (size_t ki=0; ki<small_surf.assos_points_.size(); ++ki) + { + for (size_t kj=0; kj<small_surf.assos_points_[ki].size(); ++kj) + { + Vector3D xyz = small_surf.assos_points_[ki][kj]->getPoint(); + Point pos(xyz[0], xyz[1], xyz[2]); + + double mind = std::numeric_limits<double>::max(); + int min_ix = -1; + for (size_t kr=0; kr<surfs.size(); ++kr) + { + double upar, vpar, dist; + Point close; + surfs[kr]->closestPoint(pos, upar, vpar, close, dist, eps); + if (dist < mind) + { + mind = dist; + min_ix = (int)kr; + } + } + if (min_ix >= 0) + { + points[min_ix][ki].push_back(small_surf.assos_points_[ki][kj]); + bb[min_ix][ki].addUnionWith(pos); + } + } + } + } + + for (size_t ki=0; ki<surfs.size(); ++ki) + { + size_t npt = 0; + for (size_t kj=0; kj<points[ki].size(); ++kj) + npt += points[ki][kj].size(); + if ((int)npt < min_num_pt) + { + for (size_t kj=0; kj<points[ki].size(); ++kj) + if (points[ki][kj].size() > 0) + non_assigned_pts.insert(non_assigned_pts.end(), points[ki][kj].begin(), + points[ki][kj].end()); + continue; + } + + shared_ptr<ElementarySurface> curr_sf; + bool type_cyl = (surfs[ki]->instanceType() == Class_Cylinder || + surfs[ki]->instanceType() == Class_Cone); + if (points[ki].size() > 1) + { + // Recompute free surface parameters + vector<RevEngPoint*> all_points; + for (size_t kj=0; kj<points[ki].size(); ++kj) + all_points.insert(all_points.end(), points[ki][kj].begin(), + points[ki][kj].end()); + double diag = bbox_.low().dist(bbox_.high()); + curr_sf = RevEngUtils::elemsurfWithAxis(surfs[ki], all_points, mainaxis_, diag); + } + else + curr_sf = surfs[ki]; + + // Check accuracy and extract point groups with a large distance. + size_t num_points = 0; + double maxdist = 0.0, avdist = 0.0; + int num_in = 0, num2_in = 0; + vector<vector<double> > parvals; + vector<vector<pair<double,double> > > dist_ang; + bool OK = checkAccuracy(nosf_reg[0], min_num_pt, approx_tol_, angtol, + curr_sf, points[ki], bb[ki], + num_points, maxdist, avdist, num_in, num2_in, + parvals, dist_ang, non_assigned_pts); + + if (!OK) + continue; + +#ifdef DEBUG_SMALL + std::ofstream of1("cand_sf_points.g2"); + curr_sf->writeStandardHeader(of1); + curr_sf->write(of1); + for (size_t kv=0; kv<points[ki].size(); ++kv) + { + if (points[ki][kv].size() > 0) + { + of1 << "400 1 0 0" << std::endl; + of1 << points[ki][kv].size() << std::endl; + for (size_t kw=0; kw<points[ki][kv].size(); ++kw) + of1 << points[ki][kv][kw]->getPoint() << std::endl; + } + } +#endif + double distlim = 2.0*approx_tol_; + if (maxdist > distlim) + { + // Remove the most distant points and try again + int num2 = 0; + for (size_t kj=0; kj<points[ki].size(); ++kj) + { + bb[ki][kj] = BoundingBox(3); + for (size_t kr=0; kr<points[ki][kj].size(); ) + { + if (dist_ang[kj][kr].first > distlim) + points[ki][kj].erase(points[ki][kj].begin()+kr); + else + { + Vector3D xyz = points[ki][kj][kr]->getPoint(); + Point pos(xyz[0], xyz[1], xyz[2]); + bb[ki][kj].addUnionWith(pos); + num2++; + ++kr; + } + } + } + if (num2 < min_num_pt) + continue; + + // Recompute free surface parameters + vector<RevEngPoint*> all_points; + for (size_t kj=0; kj<points[ki].size(); ++kj) + all_points.insert(all_points.end(), points[ki][kj].begin(), + points[ki][kj].end()); + double diag = bbox_.low().dist(bbox_.high()); + shared_ptr<ElementarySurface> curr_sf2; + curr_sf2 = RevEngUtils::elemsurfWithAxis(curr_sf, all_points, mainaxis_, diag); + std::swap(curr_sf, curr_sf2); + + OK = checkAccuracy(nosf_reg[0], min_num_pt, approx_tol_, angtol, + curr_sf, points[ki], bb[ki], + num_points, maxdist, avdist, num_in, num2_in, + parvals, dist_ang, non_assigned_pts); + + if (!OK) + continue; + +#ifdef DEBUG_SMALL + std::ofstream of3("cand_sf_points2.g2"); + curr_sf->writeStandardHeader(of3); + curr_sf->write(of3); + for (size_t kv=0; kv<points[ki].size(); ++kv) + { + if (points[ki][kv].size() > 0) + { + of3 << "400 1 0 0" << std::endl; + of3 << points[ki][kv].size() << std::endl; + for (size_t kw=0; kw<points[ki][kv].size(); ++kw) + of3 << points[ki][kv][kw]->getPoint() << std::endl; + } + } +#endif + } + + // Compute parameter domains + vector<RectDomain> dom(parvals.size()); + for (size_t kj=0; kj<parvals.size(); ++kj) + { + Vector2D c1(parvals[kj][0], parvals[kj][1]); + Vector2D c2(parvals[kj][0], parvals[kj][1]); + for (size_t kr=2; kr<parvals[kj].size(); kr+=2) + { + c1[0] = std::min(c1[0], parvals[kj][kr]); + c2[0] = std::max(c2[0], parvals[kj][kr]); + c1[1] = std::min(c1[1], parvals[kj][kr+1]); + c2[1] = std::max(c2[1], parvals[kj][kr+1]); + } + dom[kj] = RectDomain(c1, c2); + } + + // Sort groups according to size + RectDomain totdom = dom[0]; + vector<double> urange(dom.size()); + vector<double> vrange(dom.size()); + vector<double> diag(dom.size()); + vector<size_t> perm(points[ki].size()); + for (size_t kj=0; kj<perm.size(); ++kj) + { + perm[kj] = kj; + totdom.addUnionWith(dom[kj]); + urange[kj] = dom[kj].umax() - dom[kj].umin(); + vrange[kj] = dom[kj].vmax() - dom[kj].vmin(); + diag[kj] = bb[ki][kj].low().dist(bb[ki][kj].high()); + } + for (size_t kj=0; kj<perm.size(); ++kj) + for (size_t kr=kj+1; kr<perm.size(); ++kr) + if (points[ki][perm[kr]].size() > points[ki][perm[kj]].size()) + std::swap(perm[kr], perm[kj]); + + vector<size_t> first_group; + size_t ix = 0; + first_group.push_back(ix); + size_t kj=0, kr=0, kh=0, kv=0; + for (kj=0; kj<perm.size(); kj=kr) + { + for (kr=kj+1, kv=kj+2; kr<perm.size(); ) + { + for (kh=ix; kh<kr; ++kh) + { + double udel = 0.125*(urange[perm[kr]]+urange[perm[kh]]); + double vdel = 0.125*(vrange[perm[kr]]+vrange[perm[kh]]); + double ddel = 0.125*(diag[perm[kr]]+diag[perm[kh]]); + if (dom[perm[kh]].overlap(dom[perm[kr]], udel, vdel) && + bb[ki][perm[kh]].overlaps(bb[ki][perm[kr]], ddel)) + break; + } + if (kh >= kr) + { + // Not close + if (kv >= perm.size()) + { + ix = kr; + first_group.push_back(ix); + break; + } + if (kr < perm.size()-1) + std::swap(perm[kr], perm[kv]); + ++kv; + } + else + { + ++kr; + kv = kr+1; + } + } + } + first_group.push_back(perm.size()); + +#ifdef DEBUG_SMALL + std::ofstream of2("cand_sf_points4.g2"); + curr_sf->writeStandardHeader(of2); + curr_sf->write(of2); + for (size_t kj=1; kj<first_group.size(); ++kj) + { + size_t num = 0; + for (size_t kv=first_group[kj-1]; kv<first_group[kj]; ++kv) + num += points[ki][perm[kv]].size(); + of2 << "400 1 0 0" << std::endl; + of2 << num << std::endl; + for (size_t kv=first_group[kj-1]; kv<first_group[kj]; ++kv) + for (size_t kw=0; kw<points[ki][perm[kv]].size(); ++kw) + of2 << points[ki][perm[kv]][kw]->getPoint() << std::endl; + } +#endif + for (size_t kj=1; kj<first_group.size(); ++kj) + { + size_t num = 0; + for (size_t kv=first_group[kj-1]; kv<first_group[kj]; ++kv) + num += points[ki][perm[kv]].size(); + + if (num < min_num_pt) + { + for (size_t kv=first_group[kj-1]; kv<first_group[kj]; ++kv) + if (points[ki][perm[kv]].size() > 0) + non_assigned_pts.insert(non_assigned_pts.end(), + points[ki][perm[kv]].begin(), + points[ki][perm[kv]].end()); + } + else + { + // Create region with associated surface + // First remove the associated points from their previous region + // Collect points with respect to regions + vector<vector<RevEngPoint*> > reg_points; + for (size_t kv=first_group[kj-1]; kv<first_group[kj]; ++kv) + for (size_t kw=0; kw<points[ki][perm[kv]].size(); ++kw) + { + RevEngPoint *currpt = points[ki][perm[kv]][kw]; + RevEngRegion *reg = currpt->region(); + size_t kr; + for (kr=0; kr<reg_points.size(); ++kr) + if (reg_points[kr][0]->region() == reg) + break; + if (kr < reg_points.size()) + reg_points[kr].push_back(currpt); + else + { + vector<RevEngPoint*> curr_reg_pt; + curr_reg_pt.push_back(currpt); + reg_points.push_back(curr_reg_pt); + } + } + + for (size_t kr=0; kr<reg_points.size(); ++kr) + { + RevEngRegion *reg = reg_points[kr][0]->region(); + reg->removePoints(reg_points[kr]); + } + + // Collect points and set parameter value + vector<RevEngPoint*> surf_pts; + for (size_t kv=first_group[kj-1]; kv<first_group[kj]; ++kv) + for (size_t kw=0; kw<points[ki][perm[kv]].size(); ++kw) + { + RevEngPoint *currpt = points[ki][perm[kv]][kw]; + double u1 = parvals[perm[kv]][2*kw]; + double v1 = parvals[perm[kv]][2*kw+1]; + currpt->setPar(Vector2D(u1,v1)); + double dd = dist_ang[perm[kv]][kw].first; + double ang = dist_ang[perm[kv]][kw].second; + currpt->setSurfaceDist(dd, ang); + surf_pts.push_back(currpt); + } + + shared_ptr<RevEngRegion> small_reg(new RevEngRegion(classtype, + edge_class_type_, + surf_pts)); + shared_ptr<HedgeSurface> hedge(new HedgeSurface(curr_sf, small_reg.get())); + small_reg->setHedge(hedge.get()); + small_reg->updateInfo(approx_tol_, angtol); + int sf_flag = small_reg->defineSfFlag(0, approx_tol_, num_in, num2_in, + avdist, type_cyl); + small_reg->setSurfaceFlag(sf_flag); + small_sf_reg.push_back(small_reg); + small_sf_hedge.push_back(hedge); + + + int stop_remove = 1; + } + } + int stop_break = 1; + } +} + + + +//=========================================================================== +bool RevEng::identifySmallRotational(vector<RevEngPoint*>& points, + Point midp, Point loc0, Point axis, Point Cx, + double ppar1, double ppar2, + vector<shared_ptr<ElementarySurface> >& sfs) +//=========================================================================== +{ + double eps = 1.0e-9; + bool found = false; + double num_fac = 0.5; + double anglim2 = 5*anglim_; //10*anglim_; + int num_pt_lim = min_point_region_/20; + vector<pair<vector<RevEngPoint*>::iterator, + vector<RevEngPoint*>::iterator> > group_points; + group_points.push_back(std::make_pair(points.begin(), points.end())); + + if (loc0.dimension() == 0) + { + // Define point from cylinder algorithm + Point low = bbox_.low(); + Point high = bbox_.high(); + shared_ptr<Cylinder> tmp_cyl = + RevEngUtils::cylinderWithAxis(points, axis, low, high, mainaxis_); + loc0 = tmp_cyl->location(); + } + Point loc = loc0 + ((midp - loc0)*axis)*axis; + + vector<Point> rotated; + RevEngUtils::rotateToPlane(group_points, Cx, axis, loc, rotated); + Point loc1 = loc + ppar1*axis; + Point loc2 = loc + ppar2*axis; +#ifdef DEBUG_SMALL + std::ofstream of4("axis_rotate.g2"); + of4 << "400 1 0 4 255 0 0 255" << std::endl; + of4 << rotated.size() << std::endl; + for (size_t kr=0; kr<rotated.size(); ++kr) + of4 << rotated[kr] << std::endl; + + of4 << "410 1 0 0" << std::endl; + of4 << "1" << std::endl; + of4 << loc1 << " " << loc2 << std::endl; +#endif + + // Parameterize rotated points on axis + shared_ptr<SplineCurve> line_cv(new SplineCurve(loc1, loc2)); + vector<double> pts; + vector<double> param; + vector<double> distance; + double tmin = line_cv->startparam(); + double tmax = line_cv->endparam(); + double tmin2 = tmax; + double tmax2 = tmin; + for (size_t ki=0; ki<rotated.size(); ++ki) + { + double tpar, dist; + Point close; + line_cv->closestPoint(rotated[ki], tmin, tmax, tpar, close, dist); + pts.insert(pts.end(), rotated[ki].begin(), rotated[ki].end()); + param.push_back(tpar); + distance.push_back(dist); + tmin2 = std::min(tmin2, tpar); + tmax2 = std::max(tmax2, tpar); + } + + if (tmax2 - tmin2 < eps) + return false; + + // Statistics + int num_del = 10; + double tdel = (tmax2 - tmin2)/(double)(num_del); + vector<int> num_pts(num_del, 0); + vector<double> min_dist(num_del, std::numeric_limits<double>::max()); + vector<double> max_dist(num_del, std::numeric_limits<double>::lowest()); + vector<double> avdist(num_del, 0.0); + for (size_t kj=0; kj<param.size(); ++kj) + { + int ka = (int)((param[kj]-tmin2)/tdel); + if (ka >= (int)num_pts.size()) + ka = (int)num_pts.size() - 1; + num_pts[ka]++; + min_dist[ka] = std::min(min_dist[ka], distance[kj]); + max_dist[ka] = std::max(max_dist[ka], distance[kj]); + avdist[ka] += distance[kj]; + } + + vector<double> range(num_del); + vector<double> var(num_del); + vector<double> bddist(num_del); + vector<double> rfrac(num_del); + double avnum = 0.0, avrange = 0.0, avbdd = 0.0, avrfrac = 0.0; + double fac = 1.0/(double)num_del; + for (size_t kj=0; kj<avdist.size(); ++kj) + { + if (num_pts[kj] > 0) + avdist[kj] /= (double)num_pts[kj]; + range[kj] = max_dist[kj] - min_dist[kj]; + var[kj] = 0.5*(min_dist[kj]+max_dist[kj]) - avdist[kj]; + bddist[kj] = std::min(avdist[kj]-min_dist[kj], max_dist[kj]-avdist[kj]); + rfrac[kj] = range[kj]/(double)num_pts[kj]; + avnum += fac*(double)num_pts[kj]; + avrange += fac*range[kj]; + avbdd += fac*bddist[kj]; + avrfrac += fac*rfrac[kj]; + } + double bdfrac = avbdd/avrange; + + double numfac = 1.5; + double rfac = 1.5; + double rffac = 5.0; // Need another criterion + + // Shorten curve + double tmin3 = tmin2, tmax3 = tmax2; + for (int ka=0; ka<num_del; ++ka) + { + if (((double)num_pts[ka] > numfac*avnum || rfrac[ka] > rffac*avrfrac) && + range[ka] > rfac*avrange && bddist[ka]/range[ka] > bdfrac) + tmin3 += tdel; + else + break; + } + for (int ka=num_del-1; ka>=0; --ka) + { + if (((double)num_pts[ka] > numfac*avnum || rfrac[ka] > rffac*avrfrac) && + range[ka] > rfac*avrange && bddist[ka]/range[ka] > bdfrac) + tmax3 -= tdel; + else + break; + } + + if (tmin3 >= tmax3) + return found; + + vector<Point> rotated2; + vector<double> param2; + if (tmin3 > tmin2 || tmax3 < tmax2) + { + for (size_t ki=0; ki<param.size(); ++ki) + if (param[ki] >= tmin3 && param[ki] <= tmax3) + { + rotated2.push_back(rotated[ki]); + param2.push_back(param[ki]); + } + } + else + { + rotated2 = rotated; + param2 = param; + } + + int in = 12; + int ik = 3; + shared_ptr<SplineCurve> approx_cv; + RevEngUtils::curveApprox(rotated2, param2, ik, in, approx_cv); + +#ifdef DEBUG_SMALL + approx_cv->writeStandardHeader(of4); + approx_cv->write(of4); +#endif + + shared_ptr<SplineCurve> approx_line0; + RevEngUtils::curveApprox(rotated2, param2, 2, 2, approx_line0); + +#ifdef DEBUG_SMALL + approx_line0->writeStandardHeader(of4); + approx_line0->write(of4); +#endif + + // Check accuracy of line + vector<Point> der0(2); + approx_line0->point(der0, + 0.5*(approx_line0->startparam()+approx_line0->endparam()), 1); + shared_ptr<Line> curr_line0(new Line(der0[0], der0[1])); + + double maxdist0, avdist0; + int num_in0; + vector<double> curr_dist0; + RevEngUtils::distToCurve(rotated, curr_line0, approx_tol_, maxdist0, + avdist0, num_in0, curr_dist0); + if (num_in0 > (int)rotated.size()/2 && avdist0 <= approx_tol_) + { + // Define surface + double ang = der0[1].angle(axis); + ang = std::min(ang, M_PI-ang); + Point axis_pt = loc + ((der0[0]-loc)*axis)*axis; + double rad = der0[0].dist(axis_pt); + if (ang < anglim2) + { + // Create cylinder + shared_ptr<Cylinder> cyl(new Cylinder(rad, axis_pt, axis, Cx)); + sfs.push_back(cyl); + } + else + { + // Create cone + // Sign of angle + Point pos3; + approx_line0->point(pos3, approx_line0->endparam()); + Point axis_pt2 = loc + ((pos3-loc)*axis)*axis; + double rad2 = pos3.dist(axis_pt2); + int sgn = ((pos3 - der0[0])*axis < 0.0) ? -1 : 1; + if (sgn*rad2 < sgn*rad) + ang *= -1; + + shared_ptr<Cone> cone(new Cone(rad, axis_pt, axis, Cx, ang)); + sfs.push_back(cone); + } + return true; + } + + // Angle between consecutive control segments + vector<double> seg_ang(in-2); + vector<double> coefs(approx_cv->coefs_begin(), approx_cv->coefs_end()); + int dim = 3; + Point pt1(coefs.begin(), coefs.begin()+dim); + Point pt2(coefs.begin()+dim, coefs.begin()+2*dim); + for (int ka=2; ka<in; ++ka) + { + Point pt3(coefs.begin()+ka*dim,coefs.begin()+(ka+1)*dim); + Point vec1 = pt2 - pt1; + Point vec2 = pt3 - pt2; + seg_ang[ka-2] = vec1.angle(vec2); + pt1 = pt2; + pt2 = pt3; + } + + // Potential lines + vector<vector<Point> > line_coefs; + vector<vector<double> > line_par; + vector<Point> currc; + vector<double> currp; + for (int ka=0; ka<(int)seg_ang.size(); ++ka) + { + if (seg_ang[ka] > anglim2) + { + if (currc.size() > 0) + { + line_coefs.push_back(currc); + line_par.push_back(currp); + currc.clear(); + currp.clear(); + } + } + else + { + if (currc.size() == 0) + { + currc.push_back(Point(coefs.begin()+ka*dim,coefs.begin()+(ka+1)*dim)); + currc.push_back(Point(coefs.begin()+(ka+1)*dim,coefs.begin()+(ka+2)*dim)); + currp.push_back(approx_cv->basis().grevilleParameter(ka)); + currp.push_back(approx_cv->basis().grevilleParameter(ka+1)); + } + currc.push_back(Point(coefs.begin()+(ka+2)*dim,coefs.begin()+(ka+3)*dim)); + currp.push_back(approx_cv->basis().grevilleParameter(ka+2)); + + } + } + + if (line_par.size() == 0) + { + if (currp.size() < 2 || currp[currp.size()-1] - currp[0] < eps) + return false; + vector<double> tmp_par(2); + tmp_par[0] = currp[0]; + tmp_par[1] = currp[currp.size()-1]; + line_par.push_back(tmp_par); + } + + for (size_t kj=0; kj<line_par.size(); ++kj) + { + double tmin4 = line_par[kj][0]; + double tmax4 = line_par[kj][line_par[kj].size()-1]; + vector<Point> rotated3; + vector<double> param3; + if (tmin4 > tmin3 || tmax4 < tmax3) + { + for (size_t kr=0; kr<param2.size(); ++kr) + if (param2[kr] >= tmin4 && param2[kr] <= tmax4) + { + rotated3.push_back(rotated2[kr]); + param3.push_back(param2[kr]); + } + } + else + { + rotated3 = rotated2; + param3 = param2; + } + + if ((int)rotated3.size() < num_pt_lim) + continue; + + shared_ptr<SplineCurve> approx_line; + RevEngUtils::curveApprox(rotated3, param3, 2, 2, approx_line); + +#ifdef DEBUG_SMALL + approx_line->writeStandardHeader(of4); + approx_line->write(of4); +#endif + + // Check accuracy for all points + vector<Point> der(2); + approx_line->point(der, + 0.5*(approx_line->startparam()+approx_line->endparam()), 1); + shared_ptr<Line> curr_line(new Line(der[0], der[1])); + + double maxdist, avdist; + int num_in; + vector<double> curr_dist; + RevEngUtils::distToCurve(rotated, curr_line, approx_tol_, maxdist, + avdist, num_in, curr_dist); + + // double rad = 0.0; + // for (size_t kr=0; kr<curr_dist.size(); ++kr) + // { + // if (curr_dist[kr] <= approx_tol_) + // { + // Point tmp = loc + ((rotated[kr]-loc)*axis)*axis; + // double rad0 = rotated[kr].dist(tmp); + // rad += rad0; + // } + // } + // rad /= (double)num_in; + +#ifdef DEBUG_SMALL + std::ofstream of1("in_out_curr.g2"); + vector<Point> in_pt, out_pt; + for (size_t kr=0; kr<curr_dist.size(); ++kr) + { + if (curr_dist[kr] <= approx_tol_) + in_pt.push_back(rotated[kr]); + else + out_pt.push_back(rotated[kr]); + } + if (in_pt.size() > 0) + { + of1 << "400 1 0 4 255 0 0 255" << std::endl; + of1 << in_pt.size() << std::endl; + for (size_t kr=0; kr<in_pt.size(); ++kr) + of1 << in_pt[kr] << std::endl; + } + if (out_pt.size() > 0) + { + of1 << "400 1 0 4 0 255 0 255" << std::endl; + of1 << out_pt.size() << std::endl; + for (size_t kr=0; kr<out_pt.size(); ++kr) + of1 << out_pt[kr] << std::endl; + } +#endif + + // Remove most distant points and try again + double dlim = 2.0*approx_tol_; + vector<Point> rotated4; + vector<double> param4; + for (size_t kr=0; kr<curr_dist.size(); ++kr) + { + if (curr_dist[kr] <= dlim) + { + rotated4.push_back(rotated[kr]); + param4.push_back(param[kr]); + } + } + + shared_ptr<SplineCurve> approx_line2; + RevEngUtils::curveApprox(rotated4, param4, 2, 2, approx_line2); + +#ifdef DEBUG_SMALL + std::ofstream of2("in_out2_curr.g2"); + approx_line2->writeStandardHeader(of2); + approx_line2->write(of2); +#endif + + // Check accuracy for all points + vector<Point> der2(2); + approx_line2->point(der2, + 0.5*(approx_line2->startparam()+approx_line2->endparam()), 1); + shared_ptr<Line> curr_line2(new Line(der2[0], der2[1])); + + double maxdist2, avdist2; + int num_in2; + vector<double> curr_dist2; + RevEngUtils::distToCurve(rotated, curr_line2, approx_tol_, maxdist2, + avdist2, num_in2, curr_dist2); + // double rad2 = 0.0; + // for (size_t kr=0; kr<curr_dist.size(); ++kr) + // { + // if (curr_dist2[kr] <= approx_tol_) + // { + // Point tmp = loc + ((rotated[kr]-loc)*axis)*axis; + // double rad0 = rotated[kr].dist(tmp); + // rad2 += rad0; + // } + // } + // rad2 /= (double)num_in2; + +#ifdef DEBUG_SMALL + vector<Point> in_pt2, out_pt2; + for (size_t kr=0; kr<curr_dist2.size(); ++kr) + { + if (curr_dist2[kr] <= approx_tol_) + in_pt2.push_back(rotated[kr]); + else + out_pt2.push_back(rotated[kr]); + } + if (in_pt.size() > 0) + { + of2 << "400 1 0 4 255 0 0 255" << std::endl; + of2 << in_pt2.size() << std::endl; + for (size_t kr=0; kr<in_pt2.size(); ++kr) + of2 << in_pt2[kr] << std::endl; + } + if (out_pt2.size() > 0) + { + of2 << "400 1 0 4 0 255 0 255" << std::endl; + of2 << out_pt2.size() << std::endl; + for (size_t kr=0; kr<out_pt2.size(); ++kr) + of2 << out_pt2[kr] << std::endl; + } +#endif + + // Define surface + if ((double)(std::max(num_in0, std::max(num_in, num_in2))) < + num_fac*(double)rotated2.size()) + continue; + if (num_in0 > std::max(num_in, num_in2)) + { + //std::swap(rad, rad2); + std::swap(der0[0], der2[0]); + std::swap(der0[1], der2[1]); + } + else if (num_in > num_in2) + { + //std::swap(rad, rad2); + std::swap(der[0], der2[0]); + std::swap(der[1], der2[1]); + } + if (std::max(num_in0, std::max(num_in, num_in2)) > num_pt_lim) + { + double ang = der2[1].angle(axis); + ang = std::min(ang, M_PI-ang); + Point axis_pt = loc + ((der2[0]-loc)*axis)*axis; + double rad = der2[0].dist(axis_pt); + if (ang < anglim2) + { + // Create cylinder + shared_ptr<Cylinder> cyl(new Cylinder(rad, axis_pt, axis, Cx)); + sfs.push_back(cyl); + } + else + { + // Create cone + // Sign of angle + Point pos3; + if (num_in2 > num_in) + approx_line2->point(pos3, approx_line2->endparam()); + else + approx_line->point(pos3, approx_line->endparam()); + Point axis_pt2 = loc + ((pos3-loc)*axis)*axis; + double rad2 = pos3.dist(axis_pt2); + int sgn = ((pos3 - der[0])*axis < 0.0) ? -1 : 1; + if (sgn*rad2 < sgn*rad) + ang *= -1; + + shared_ptr<Cone> cone(new Cone(rad, axis_pt, axis, Cx, ang)); + sfs.push_back(cone); + } + found = true; + } + } + + return found; +} + +//=========================================================================== +bool RevEng::identifySmallPlanar(vector<RevEngPoint*>& points, + Point loc, Point axis, Point Cx, + double ppar1, double ppar2, double delta, + vector<shared_ptr<ElementarySurface> >& sfs) +//=========================================================================== +{ + // Sort groups with respect to axis + vector<Point> axis_pt(points.size()); + vector<double> axis_par(points.size()); + double tmin = std::numeric_limits<double>::max(); + double tmax = std::numeric_limits<double>::lowest(); + double avpar = 0.0; + for (size_t ki=0; ki<points.size(); ++ki) + { + Vector3D xyz = points[ki]->getPoint(); + Point pos(xyz[0], xyz[1], xyz[2]); + double tpar = (pos - loc)*axis; + tmin = std::min(tmin, tpar); + tmax = std::max(tmax, tpar); + axis_par[ki] = tpar; + axis_pt[ki] = loc + axis_par[ki]*axis; + } + + size_t ki; + double tlim = 1.5*approx_tol_; + int nlim = 100; // Currently + double angtol = 5.0*anglim_; + bool found = false; + int num = 0; + Point mid(0.0, 0.0, 0.0); + for (ki=0; ki<axis_par.size(); ++ki) + { + if (axis_par[ki] <= ppar1+delta || axis_par[ki] >= ppar2-delta) + continue; + + Point vec = axis_pt[ki] - loc; + Point pos2 = loc + (vec*axis)*axis; + mid += pos2; + ++num; + } + + if (num == 0) + return false; + mid /= (double)num; + + shared_ptr<Plane> plane(new Plane(mid, axis, Cx)); +#ifdef DEBUG_SMALL + std::ofstream of("small_plane.g2"); + plane->writeStandardHeader(of); + plane->write(of); +#endif + + // Check accuracy + double maxd, avd; + int n_in, n2_in; + vector<double> parvals; + vector<pair<double,double> > distang; + vector<RevEngPoint*> in, out; + RevEngUtils::distToSurf(points, plane, approx_tol_, angtol, + maxd, avd, n_in, n2_in, distang); + + if (avd <= approx_tol_ && n2_in > points.size()/2) + { + sfs.push_back(plane); + found = true; + } + return found; +} + +//=========================================================================== +bool RevEng::identifySmallPlanar(vector<RevEngRegion*>& groups, + Point loc, Point axis, Point Cx, + double ppar1, double ppar2, double delta, + vector<shared_ptr<ElementarySurface> >& sfs) +//=========================================================================== +{ + // Sort groups with respect to axis + vector<Point> axis_pt(groups.size()); + vector<double> axis_par(groups.size()); + vector<pair<double,double> > axis_range(groups.size()); + for (size_t ki=0; ki<groups.size(); ++ki) + { + int num = groups[ki]->numPoints(); + double tmin = std::numeric_limits<double>::max(); + double tmax = std::numeric_limits<double>::lowest(); + double avpar = 0.0; + double fac = 1.0/(double)num; + for (int ka=0; ka<num; ++ka) + { + Vector3D xyz = groups[ki]->getPoint(ka)->getPoint(); + Point pos(xyz[0], xyz[1], xyz[2]); + double tpar = (pos - loc)*axis; + tmin = std::min(tmin, tpar); + tmax = std::max(tmax, tpar); + avpar += fac*tpar; + } + axis_par[ki] = avpar; + axis_range[ki] = std::make_pair(tmin,tmax); + axis_pt[ki] = loc + axis_par[ki]*axis; + } + + for (size_t ki=0; ki<groups.size(); ++ki) + for (size_t kj=ki+1; kj<groups.size(); ++kj) + { + if (axis_par[kj] < axis_par[ki]) + { + std::swap(axis_par[ki], axis_par[kj]); + std::swap(axis_pt[ki], axis_pt[kj]); + std::swap(axis_range[ki], axis_range[kj]); + std::swap(groups[ki], groups[kj]); + } + } + + size_t ki, kj; + double tlim = 1.5*approx_tol_; + int nlim = 100; // Currently + double angtol = 5.0*anglim_; + bool found = false; + for (ki=0; ki<axis_par.size(); ki=kj) + { + for (kj=ki+1; kj<axis_par.size() && axis_par[kj]-axis_par[ki]<tlim; ++kj); + int num = 0; + for (size_t kr=ki; kr<kj; ++kr) + num += groups[kr]->numPoints(); + if (num < nlim) + continue; + if (axis_range[ki].second <= ppar1+delta) + continue; + if (axis_range[ki].first >= ppar2-delta) + continue; + + Point mid(0.0, 0.0, 0.0); + int nmb = 0; + for (size_t kr=ki; kr<kj; ++kr) + { + int num2 = groups[kr]->numPoints(); + for (int ka=0; ka<num2; ++ka) + { + Vector3D pos0 = groups[kr]->getPoint(ka)->getPoint(); + Point pos(pos0[0], pos0[1], pos0[2]); + double tpar = (pos - loc)*axis; + if (tpar <= ppar1+delta || tpar >= ppar2-delta) + continue; + Point vec = pos - loc; + Point pos2 = loc + (vec*axis)*axis; + mid += pos2; + ++nmb; + } + } + + if (nmb == 0) + continue; + mid /= (double)nmb; + + shared_ptr<Plane> plane(new Plane(mid, axis, Cx)); +#ifdef DEBUG_SMALL + std::ofstream of("small_plane.g2"); + plane->writeStandardHeader(of); + plane->write(of); +#endif + + // Check accuracy + double maxdist = 0.0, avdist = 0.0; + int num_in = 0, num2_in = 0; + double fac = 1.0/(double)(kj-ki); + for (size_t kr=ki; kr<kj; ++kr) + { + double maxd, avd; + int n_in, n2_in; + vector<double> parvals; + vector<pair<double,double> > distang; + vector<RevEngPoint*> in, out; + RevEngUtils::distToSurf(groups[kr]->pointsBegin(), groups[kr]->pointsEnd(), + plane, approx_tol_, maxd, avd, n_in, + n2_in, in, out, parvals, distang, angtol); + maxdist = std::max(maxdist, maxd); + avdist += fac*avd; + num_in += n_in; + num2_in += n2_in; + } + int surf_flag = groups[ki]->defineSfFlag(num, 0, approx_tol_, num_in, + num2_in, avdist, false); + if (surf_flag < NOT_SET) + { + sfs.push_back(plane); + found = true; + } + } + return found; +} + + +//=========================================================================== +void RevEng::adaptToMainAxis() +//=========================================================================== +{ + doAdaptToAxis(); + +#ifdef DEBUG + std::cout << "Post merge similar. Number of regions: " << regions_.size() << std::endl; + + checkConsistence("Regions11_1"); + + if (regions_.size() > 0) + { + std::cout << "Regions 11_1" << std::endl; + std::ofstream of("regions11_1.g2"); + std::ofstream ofm("mid_regions11_1.g2"); + std::ofstream ofs("small_regions11_1.g2"); + writeRegionStage(of, ofm, ofs); + std::ofstream of0("regions11_1_helix.g2"); + for (int ki=0; ki<(int)regions_.size(); ++ki) + { + if (regions_[ki]->getSurfaceFlag() == PROBABLE_HELIX) + { + regions_[ki]->writeRegionInfo(of0); + if (regions_[ki]->hasSurface()) + regions_[ki]->writeSurface(of0); + } + } + if (surfaces_.size() > 0) + { + std::ofstream of("regsurf11_1.g2"); + writeRegionWithSurf(of); + } + } +#endif + +#ifdef DEBUG + std::ofstream ofu1("unresolved2.g2"); + for (size_t kr=0; kr<regions_.size(); ++kr) + { + if (regions_[kr]->hasSurface()) + continue; + if (regions_[kr]->hasAssociatedBlend()) + continue; + regions_[kr]->writeRegionPoints(ofu1); + } +#endif + + // Merge adjacent edges if possible + double eps = 1.0e-9; + for (int ka=0; ka<(int)edges_.size(); ++ka) + { + RevEngRegion* adj1[2]; + edges_[ka]->getAdjacent(adj1[0], adj1[1]); + for (int kb=ka+1; kb<(int)edges_.size(); ++kb) + { + RevEngRegion* adj2[2]; + edges_[kb]->getAdjacent(adj2[0], adj2[1]); + + if ((adj1[0] == adj2[0] || adj1[0] == adj2[1]) && + (adj1[1] == adj2[0] || adj1[1] == adj2[1])) + { + double par1, par2; + bool adjacent = edges_[ka]->isAdjacent(edges_[kb].get(), + approx_tol_, par1, par2); + if (adjacent) + { +#ifdef DEBUG_BLEND + std::ofstream of("adj_blend.g2"); + adj1[0]->writeRegionPoints(of); + adj1[1]->writeRegionPoints(of); + vector<shared_ptr<ParamCurve> > cvs1 = edges_[ka]->getSpaceCurves(); + for (size_t kh=0; kh<cvs1.size(); ++kh) + { + cvs1[kh]->writeStandardHeader(of); + cvs1[kh]->write(of); + } + vector<shared_ptr<ParamCurve> > cvs2 = edges_[kb]->getSpaceCurves(); + for (size_t kh=0; kh<cvs2.size(); ++kh) + { + cvs2[kh]->writeStandardHeader(of); + cvs2[kh]->write(of); + } + +#endif + // Check for seam of adjacent surface + shared_ptr<ParamSurface> surf1 = adj1[0]->getSurface(0)->surface(); + shared_ptr<ParamSurface> surf2 = adj1[1]->getSurface(0)->surface(); + shared_ptr<ElementarySurface> elem1 = + dynamic_pointer_cast<ElementarySurface,ParamSurface>(surf1); + shared_ptr<ElementarySurface> elem2 = + dynamic_pointer_cast<ElementarySurface,ParamSurface>(surf2); + bool close1=false, close2=false, close3=false, close4=false; + if (elem1.get()) + elem1->isClosed(close1, close2); + if (elem2.get()) + elem2->isClosed(close3, close4); + Point pos = edges_[ka]->point(par1); + if (close1 || close2) + { + RectDomain dom = elem1->containingDomain(); + double upar, vpar, dist; + Point close_pt; + elem1->closestBoundaryPoint(pos, upar, vpar, close_pt, dist, eps); + if (dist < approx_tol_) + { + if (close1 && (fabs(upar-dom.umin()) < eps || fabs(dom.umax()-upar) < eps)) + adjacent = false; + if (close2 && (fabs(vpar-dom.vmin()) < eps || fabs(dom.vmax()-vpar) < eps)) + adjacent = false; + } + } + + if (close3 || close4) + { + RectDomain dom = elem2->containingDomain(); + double upar, vpar, dist; + Point close_pt; + elem2->closestBoundaryPoint(pos, upar, vpar, close_pt, dist, eps); + if (dist < approx_tol_) + { + if (close3 && (fabs(upar-dom.umin()) < eps || fabs(dom.umax()-upar) < eps)) + adjacent = false; + if (close4 && (fabs(vpar-dom.vmin()) < eps || fabs(dom.vmax()-vpar) < eps)) + adjacent = false; + } + } + } + + if (adjacent) + { + double t1 = edges_[ka]->startparam(); + double t2 = edges_[ka]->endparam(); + if (fabs(par1-t1) < fabs(par2-t2)) + std::swap(edges_[ka], edges_[kb]); + bool done = edges_[ka]->append(edges_[kb].get(), approx_tol_); + if (done) + { + edges_.erase(edges_.begin()+kb); + kb--; + } + int stop_break0 = 1; + } + } + } + } + + int stop_break = 1; + +} + +//=========================================================================== +void RevEng::doAdaptToAxis() +//=========================================================================== +{ + vector<SurfaceProperties> sfprop; + collectAxis(sfprop); + + // Sort surfaces into groups with roughly the same axis + double epsang = 0.05; + double eps = 1.0e-4; + vector<DirectionCone> axis_cone; + vector<vector<size_t> > group_ixs; + vector<int> num_pts; + for (size_t ki=0; ki<sfprop.size(); ++ki) + { + if (sfprop[ki].type_ == Class_Sphere) + continue; // Sphere centre is relevant, axis is derived + size_t kr; + for (kr=0; kr<axis_cone.size(); ++kr) + { + Point centre = axis_cone[kr].centre(); + if (sfprop[ki].dir_*centre < 0.0) + sfprop[ki].dir_ *= -1; + Point axis = sfprop[ki].dir_; + double angle = axis_cone[kr].unionAngle(axis); + if (angle <= epsang) + { + axis_cone[kr].addUnionWith(axis); + group_ixs[kr].push_back(ki); + num_pts[kr] += sfprop[ki].num_points_; + break; + } + } + if (kr == axis_cone.size()) + { + DirectionCone cone(sfprop[ki].dir_); + axis_cone.push_back(cone); + vector<size_t> ixs; + ixs.push_back(ki); + group_ixs.push_back(ixs); + num_pts.push_back(sfprop[ki].num_points_); + } + } + + // Sort according to number of points associated to the surface + for (size_t ki=0; ki<num_pts.size(); ++ki) + for (size_t kj=ki+1; kj<num_pts.size(); ++kj) + { + if (num_pts[kj] > num_pts[ki]) + { + std::swap(num_pts[ki], num_pts[kj]); + std::swap(axis_cone[ki], axis_cone[kj]); + std::swap(group_ixs[ki], group_ixs[kj]); + } + } + + // For each group, ecompute axis direction based on reliability of surface + // type and number of points associated to the surface + double planefac = 1.0; + double cylfac = 0.75; + double conefac = 0.6; + double torfac = 0.4; + vector<Point> axes(group_ixs.size()); + for (size_t ki=0; ki<group_ixs.size(); ++ki) + { + Point curr(0.0, 0.0, 0.0); + for (size_t kj=0; kj<group_ixs[ki].size(); ++kj) + { + Point curr2 = sfprop[group_ixs[ki][kj]].dir_; + double fac = planefac; + if (sfprop[group_ixs[ki][kj]].type_ == Class_Cylinder) + fac = cylfac; + else if (sfprop[group_ixs[ki][kj]].type_ == Class_Cone) + fac = conefac; + else if (sfprop[group_ixs[ki][kj]].type_ == Class_Torus) + fac = torfac; + int num = sfprop[group_ixs[ki][kj]].num_points_; + curr += (double)num*fac*curr2; + } + if (curr.length() < eps) + axes[ki] = axis_cone[ki].centre(); + else + { + curr.normalize(); + axes[ki] = curr; + } + } + + adjustWithMainAxis(axes, num_pts); + + size_t num_axis = model_axis_.size(); + vector<RevEngEdge*> nopar_edgs; + for (size_t ki=0; ki<num_pts.size(); ++ki) + { + int ix=-1; + double min_ang = M_PI; + for (int ka=0; ka<3; ++ka) + { + double ang = axes[ki].angle(mainaxis_[ka]); + ang = std::min(ang, M_PI-ang); + if (ang < min_ang) + { + min_ang = ang; + ix = ka; + } + } + + Point Cx = mainaxis_[(ix+2)%3].cross(axes[ki]); + Cx.normalize(); + + AxisInfo curr_axis(axes[ki]); + model_axis_.push_back(curr_axis); + + // Identify surfaces with the "same" axis including location + vector<vector<int> > plane_adapt; + vector<int> num_adapt1; + for (size_t kj=0; kj<group_ixs[ki].size(); ++kj) + { + if (sfprop[group_ixs[ki][kj]].type_ != Class_Plane) + continue; + + shared_ptr<ParamSurface> surf = surfaces_[sfprop[group_ixs[ki][kj]].sfix_]->surface(); + shared_ptr<Plane> plane = dynamic_pointer_cast<Plane,ParamSurface>(surf); + Point loc = plane->location(); + + size_t kr, kh; + for (kr=0; kr<plane_adapt.size(); ++kr) + { + for (kh=0; kh<plane_adapt[kr].size(); ++kh) + { + shared_ptr<ParamSurface> surf2 = surfaces_[plane_adapt[kr][kh]]->surface(); + shared_ptr<Plane> plane2 = dynamic_pointer_cast<Plane,ParamSurface>(surf2); + Point loc2 = plane2->location(); + double dd = fabs((loc-loc2)*axes[ki]); + if (dd <= approx_tol_) + break; + } + if (kh < plane_adapt[kr].size()) + break; + } + if (kr == plane_adapt.size()) + { + vector<int> curr_adapt; + curr_adapt.push_back(sfprop[group_ixs[ki][kj]].sfix_); + plane_adapt.push_back(curr_adapt); + num_adapt1.push_back(sfprop[group_ixs[ki][kj]].num_points_); + } + else + { + plane_adapt[kr].push_back(sfprop[group_ixs[ki][kj]].sfix_); + num_adapt1[kr] += sfprop[group_ixs[ki][kj]].num_points_; + } + } + + for (size_t kj=0; kj<plane_adapt.size(); ++kj) + { + Point location = planarFit(plane_adapt[kj], axes[ki]); + model_axis_[num_axis+ki].addPlaneLocation(location, num_adapt1[kj]); + } + + // The other surfaces + vector<vector<int> > rotational_adapt; + vector<int> num_adapt2; + for (size_t kj=0; kj<group_ixs[ki].size(); ++kj) + { + if (sfprop[group_ixs[ki][kj]].type_ == Class_Plane) + continue; + + Point loc = sfprop[group_ixs[ki][kj]].loc_; + size_t kr, kh; + for (kr=0; kr<rotational_adapt.size(); ++kr) + { + for (kh=0; kh<rotational_adapt[kr].size(); ++kh) + { + shared_ptr<ParamSurface> surf2 = + surfaces_[rotational_adapt[kr][kh]]->surface(); + shared_ptr<ElementarySurface> elem = + dynamic_pointer_cast<ElementarySurface,ParamSurface>(surf2); + Point loc2 = elem->location(); + Point tmp = loc + ((loc2-loc)*axes[ki])*axes[ki]; + double dd = loc2.dist(tmp); + if (dd <= approx_tol_) + break; + } + if (kh < rotational_adapt[kr].size()) + break; + } + if (kr == rotational_adapt.size()) + { + vector<int> curr_adapt; + curr_adapt.push_back(sfprop[group_ixs[ki][kj]].sfix_); + rotational_adapt.push_back(curr_adapt); + num_adapt2.push_back(sfprop[group_ixs[ki][kj]].num_points_); + } + else + { + rotational_adapt[kr].push_back(sfprop[group_ixs[ki][kj]].sfix_); + num_adapt2[kr] += sfprop[group_ixs[ki][kj]].num_points_; + } + } + + for (size_t kj=0; kj<rotational_adapt.size(); ++kj) + { + Point location = rotationalFit(rotational_adapt[kj], axes[ki], Cx, + nopar_edgs); + if (location.dimension() > 0) + model_axis_[num_axis+ki].addRotationalLocation(location, num_adapt2[kj]); + } + } + + // Sort axes + vector<int> num_axis_pt(model_axis_.size()); + for (size_t ki=0; ki<model_axis_.size(); ++ki) + { + int num_pt = 0; + for (size_t kj=0; kj<model_axis_[ki].plane_loc_.size(); ++kj) + num_pt += model_axis_[ki].plane_loc_[kj].second; + for (size_t kj=0; kj<model_axis_[ki].rotational_loc_.size(); ++kj) + num_pt += model_axis_[ki].rotational_loc_[kj].second; + num_axis_pt[ki] = num_pt; + } + + for (size_t ki=0; ki<model_axis_.size(); ++ki) + { + for (size_t kj=ki+1; kj<model_axis_.size(); ++kj) + if (num_axis_pt[ki] < num_axis_pt[kj]) + { + std::swap(model_axis_[ki], model_axis_[kj]); + std::swap(num_axis_pt[ki], num_axis_pt[kj]); + } + } + + + if (nopar_edgs.size() > 0) + { + // Must split edge at seam + vector<shared_ptr<RevEngEdge> > added_edgs; + vector<shared_ptr<RevEngRegion> > added_regs; + vector<shared_ptr<HedgeSurface> > added_sfs; + for (size_t ki=0; ki<nopar_edgs.size(); ++ki) + { + if (nopar_edgs[ki]->isClosed(approx_tol_)) + continue; // Will be handled later + nopar_edgs[ki]->splitAtSeam(approx_tol_, added_edgs, added_regs, + added_sfs); + } + if (added_edgs.size() > 0) + edges_.insert(edges_.end(), added_edgs.begin(), added_edgs.end()); + if (added_regs.size() > 0) + regions_.insert(regions_.end(), added_regs.begin(), added_regs.end()); + if (added_sfs.size() > 0) + surfaces_.insert(surfaces_.end(), added_sfs.begin(), added_sfs.end()); + } + + int stop_break = 1; +} + +//=========================================================================== +void RevEng::adjustWithMainAxis(vector<Point>& axes, vector<int>& num_pts) +//=========================================================================== +{ + double angtol1 = 5.0*anglim_; + double angtol2 = 5.0*angtol1; + double pihalf = 0.5*M_PI; + double eps = 1.0e-6; + + // Change sign of axis if in conflict with existing main axis + for (size_t ki=0; ki<axes.size(); ++ki) + { + for (int ka=0; ka<3; ++ka) + { + double ang = axes[ki].angle(mainaxis_[ka]); + ang = std::min(ang, M_PI-ang); + double scpr = axes[ki]*mainaxis_[ka]; + if (scpr < 0.0 && ang<angtol2) + axes[ki] *= -1.0; + } + } + + vector<Point> axes2(axes.size()); + for (size_t ki=0; ki<axes.size(); ++ki) + axes2[ki] = axes[ki]; + + for (int ix1=(int)axes2.size()-1; ix1>=0; --ix1) + { + Vector3D axis1(axes2[ix1][0], axes2[ix1][1], axes2[ix1][2]); + for (int ix2=ix1-1; ix2>=0; --ix2) + { + Vector3D axis2(axes2[ix2][0], axes2[ix2][1], axes2[ix2][2]); + double ang = axes2[ix1].angle(axes2[ix2]); + double ang2 = fabs(pihalf-ang); + if (ang2 > eps && ang2 < angtol1) + { + // Adjust axes2 to achieve orthogonality + Point vec = axes2[ix1].cross(axes2[ix2]); + int sgn = (ang < pihalf) ? 1 : -1; + double fac = 1.0/(double)(num_pts[ix1] + num_pts[ix2]); + double ang3 = (double)num_pts[ix2]*fac*ang2; + double ang4 = (double)num_pts[ix1]*fac*ang2; + Matrix3D mat1, mat2; + mat1.setToRotation(-sgn*ang3, vec[0], vec[1], vec[2]); + mat2.setToRotation(sgn*ang4, vec[0], vec[1], vec[2]); + Vector3D axis3 = mat1*axis1; + Vector3D axis4 = mat2*axis2; + axis3.normalize_checked(); + axis4.normalize_checked(); + axes2[ix1] = Point(axis3[0], axis3[1], axis3[2]); + axes2[ix2] = Point(axis4[0], axis4[1], axis4[2]); + int stop_break = 1; + } + } + } + + // Ensure orthogonality + int ix1 = 0; + int ix2 = -1, ix3 = -1; + for (int ka=1; ka<(int)axes2.size(); ++ka) + { + double ang = axes2[ix1].angle(axes2[ka]); + if (fabs(pihalf-ang) < angtol1) + { + if (ix2 < 0) + ix2 = ka; + else if (ix3 < 0) + { + ix3 = ka; + break; + } + } + } + + if (ix2 < 0) + { + ix2 = (int)axes2.size(); + ix3 = (int)axes2.size()+1; + axes2.resize(axes2.size()+2); + } + else if (ix3 < 0) + { + ix3 = (int)axes2.size(); + axes2.resize(axes2.size()+1); + } + + if (ix3 > (int)axes.size()) + { + int min_ix = 0; + double min_ang = fabs(axes2[ix1].angle(mainaxis_[0])); + for (int kb=1; kb<3; ++kb) + { + double ang = fabs(axes2[ix1].angle(mainaxis_[kb])); + if (ang < min_ang) + { + min_ix = kb; + min_ang = ang; + } + } + + int min_ix2 = -1; + if (ix2 < (int)axes.size()) + { + min_ix2 = (min_ang == 0) ? 1 : 0; + double min_ang2 = fabs(axes2[ix2].angle(mainaxis_[min_ix2])); + for (int kb=0; kb<3; ++kb) + { + if (kb == min_ix || kb == min_ix2) + continue; + double ang = fabs(axes2[ix2].angle(mainaxis_[kb])); + if (ang < min_ang) + { + min_ix2 = kb; + min_ang2 = ang; + } + } + } + else + { + for (int kb=0; kb<3; ++kb) + if (kb != min_ix) + { + axes2[ix2] = mainaxis_[kb]; + min_ix2 = kb; + break; + } + } + + for (int kb=0; kb<3; ++kb) + if (kb != min_ix && kb != min_ix2) + { + axes2[ix3] = mainaxis_[kb]; + break; + } + } + + axes2[ix3] = axes2[ix1].cross(axes2[ix2]); + axes2[ix2] = axes2[ix3].cross(axes2[ix1]); + + for (size_t ki=0; ki<axes.size(); ++ki) + axes[ki] = axes2[ki]; + + mainaxis_[0] = axes2[ix1]; + mainaxis_[1] = axes2[ix2]; + mainaxis_[2] = axes2[ix3]; +} + +//=========================================================================== +Point RevEng::planarFit(vector<int>& sf_ix, Point axis) +//=========================================================================== +{ + double angtol = 5.0*anglim_; + + // Collect data points + vector<RevEngPoint*> points; + Point loc(0.0, 0.0, 0.0); + int num = 0; + for (size_t ki=0; ki<sf_ix.size(); ++ki) + { + HedgeSurface* surf = surfaces_[sf_ix[ki]].get(); + shared_ptr<Plane> plane = + dynamic_pointer_cast<Plane,ParamSurface>(surf->surface()); + if (!plane.get()) + continue; + loc += plane->location(); + num++; + vector<RevEngRegion*> reg = surf->getRegions(); + for (size_t kj=0; kj<reg.size(); ++kj) + { + points.insert(points.end(), reg[kj]->pointsBegin(), + reg[kj]->pointsEnd()); + } + } + if (num > 0) + loc /= (double)num; + + shared_ptr<Plane> plane2 = RevEngUtils::planeWithAxis(points, axis, + loc, mainaxis_); + + Point centre = plane2->location(); + Point Cx = plane2->direction2(); + + for (size_t ki=0; ki<sf_ix.size(); ++ki) + { + HedgeSurface* surf = surfaces_[sf_ix[ki]].get(); + shared_ptr<Plane> plane = + dynamic_pointer_cast<Plane,ParamSurface>(surf->surface()); + if (!plane.get()) + continue; + Point loc2 = plane->location(); + loc2 -= ((loc2-centre)*axis)*axis; + shared_ptr<Plane> plane3(new Plane(loc2, axis, Cx)); + if (plane->direction()*axis < 0.0) + plane3->swapParameterDirection(); + + vector<RevEngRegion*> reg = surf->getRegions(); + double maxdist = 0.0, avdist = 0.0; + int num_in = 0, num2_in = 0, num_pt = 0; + double maxdist_init = 0.0, avdist_init = 0.0; + int num_in_init = 0, num2_in_init = 0; + vector<vector<double> > parvals(reg.size()); + vector<vector<pair<double,double> > > dist_ang(reg.size()); + vector<int> init_flag(reg.size());; + for (size_t kj=0; kj<reg.size(); ++kj) + { + double maxd0, avd0; + int num_in0, num2_in0; + vector<RevEngPoint*> in0, out0; + vector<pair<double,double> > distang0; + vector<double> parvals0; + RevEngUtils::distToSurf(reg[kj]->pointsBegin(), reg[kj]->pointsEnd(), + plane3, approx_tol_, maxd0, avd0, num_in0, num2_in0, + in0, out0, parvals0, distang0, angtol); + int num0 = reg[kj]->numPoints(); + maxdist = std::max(maxdist, maxd0); + avdist = (double)num_pt*avdist + (double)num0*avd0; + num_in += num_in0; + num2_in += num2_in0; + parvals[kj] = parvals0; + dist_ang[kj] = distang0; + + double maxd1, avd1; + int num_in1, num2_in1; + reg[kj]->getAccuracy(maxd1, avd1, num_in1, num2_in1); + maxdist_init = std::max(maxdist_init, maxd1); + avdist_init = (double)num_pt*avdist_init + (double)num0*avd1; + num_in_init += num_in1; + num2_in_init += num2_in1; + num_pt += num0; + init_flag[kj] = reg[kj]->getSurfaceFlag(); + } + avdist /= (double)num_pt; + avdist_init /= (double)num_pt; + int surf_flag = reg[0]->defineSfFlag(num_pt, 0, approx_tol_, num_in, + num2_in, avdist, false); + int surf_flag_init = reg[0]->defineSfFlag(num_pt, 0, approx_tol_, num_in_init, + num2_in_init, avdist_init, false); + + double av_fac = 1.1; + double in_fac = 0.9; + if (surf_flag == 0 || surf_flag <= surf_flag_init || + (avdist < av_fac*avdist_init && + (double)num2_in > in_fac*(double)num2_in_init && + (double)num_in > in_fac*(double)num_in_init)) + { + // Replace surface + for (size_t kj=0; kj<reg.size(); ++kj) + { + vector<RevEngEdge*> dummy; + reg[kj]->updateSurfaceAndInfo(plane3, approx_tol_, angtol, + parvals[kj], dist_ang[kj], dummy); + } + } + + int stop_break = 1; + } + return centre; +} + +//=========================================================================== +Point RevEng::rotationalFit(vector<int>& sf_ix, Point axis, Point Cx, + vector<RevEngEdge*>& nopar_edgs) +//=========================================================================== +{ + double angtol = 5.0*anglim_; + Point dummy_loc; + + // Compute point on axis + Point loc(0.0, 0.0, 0.0); + int num = 0; + for (size_t ki=0; ki<sf_ix.size(); ++ki) + { + HedgeSurface* surf = surfaces_[sf_ix[ki]].get(); + shared_ptr<ElementarySurface> elem = + dynamic_pointer_cast<ElementarySurface,ParamSurface>(surf->surface()); + if (!elem.get()) + continue; + loc += elem->location(); + num++; + } + if (num > 0) + loc /= (double)num; + + // Add spheres with centre on axis + for (size_t ki=0; ki<surfaces_.size(); ++ki) + { + shared_ptr<ParamSurface> sf = surfaces_[ki]->surface(); + if (sf->instanceType() == Class_Sphere) + { + shared_ptr<Sphere> sphere = dynamic_pointer_cast<Sphere,ParamSurface>(sf); + Point centre = sphere->location(); + Point tmp = loc + ((centre-loc)*axis)*axis; + if (centre.dist(tmp) < approx_tol_) + sf_ix.push_back((int)ki); + } + } + + double udomain[2]; + udomain[0] = std::numeric_limits<double>::max(); + udomain[1] = std::numeric_limits<double>::lowest(); + int num_pts = 0; + for (size_t ki=0; ki<sf_ix.size(); ++ki) + { + HedgeSurface* surf = surfaces_[sf_ix[ki]].get(); + shared_ptr<ElementarySurface> elem = + dynamic_pointer_cast<ElementarySurface,ParamSurface>(surf->surface()); + if (!elem.get()) + continue; + Point loc2 = elem->location(); + Point loc2_2 = loc + ((loc2 - loc)*axis)*axis; + + vector<RevEngPoint*> points; + vector<RevEngRegion*> reg = surf->getRegions(); + for (size_t kj=0; kj<reg.size(); ++kj) + { + points.insert(points.end(), reg[kj]->pointsBegin(), + reg[kj]->pointsEnd()); + } + + shared_ptr<ElementarySurface> elem2; + if (elem->instanceType() == Class_Cylinder) + elem2 = RevEngUtils::cylinderWithAxis(points, axis, Cx, loc2_2); + else if (elem->instanceType() == Class_Cone) + { + double len = bbox_.low().dist(bbox_.high()); + elem2 = RevEngUtils::coneWithAxis(points, axis, Cx, loc2_2, len); + if (!elem2.get()) + elem2 = elem; + } + else if (elem->instanceType() == Class_Torus) + elem2 = RevEngUtils::torusWithAxis(points, axis, Cx, loc2_2); + else if (elem->instanceType() == Class_Sphere) + elem2 = RevEngUtils::sphereWithAxis(points, axis, Cx, loc2_2); + + double maxdist = 0.0, avdist = 0.0; + int num_in = 0, num2_in = 0, num_pt = 0; + double maxdist_init = 0.0, avdist_init = 0.0; + int num_in_init = 0, num2_in_init = 0; + vector<vector<double> > parvals(reg.size()); + vector<vector<pair<double,double> > > dist_ang(reg.size()); + vector<int> init_flag(reg.size());; + for (size_t kj=0; kj<reg.size(); ++kj) + { + double maxd0, avd0; + int num_in0, num2_in0; + vector<RevEngPoint*> in0, out0; + vector<pair<double,double> > distang0; + vector<double> parvals0; + RevEngUtils::distToSurf(reg[kj]->pointsBegin(), reg[kj]->pointsEnd(), + elem2, approx_tol_, maxd0, avd0, num_in0, num2_in0, + in0, out0, parvals0, distang0, angtol); + int num0 = reg[kj]->numPoints(); + maxdist = std::max(maxdist, maxd0); + avdist = (double)num_pt*avdist + (double)num0*avd0; + num_in += num_in0; + num2_in += num2_in0; + parvals[kj] = parvals0; + dist_ang[kj] = distang0; + + double maxd1, avd1; + int num_in1, num2_in1; + reg[kj]->getAccuracy(maxd1, avd1, num_in1, num2_in1); + maxdist_init = std::max(maxdist_init, maxd1); + avdist_init = (double)num_pt*avdist_init + (double)num0*avd1; + num_in_init += num_in1; + num2_in_init += num2_in1; + num_pt += num0; + init_flag[kj] = reg[kj]->getSurfaceFlag(); + } + avdist /= (double)num_pt; + avdist_init /= (double)num_pt; + + bool cyl_like = (elem->instanceType() == Class_Cylinder || + elem->instanceType() == Class_Cone); + int surf_flag = reg[0]->defineSfFlag(num_pt, 0, approx_tol_, num_in, + num2_in, avdist, cyl_like); + int surf_flag_init = reg[0]->defineSfFlag(num_pt, 0, approx_tol_, num_in_init, + num2_in_init, avdist_init, cyl_like); + + double av_fac = 1.1; + double in_fac = 0.9; + if (surf_flag == 0 || surf_flag <= surf_flag_init || + (avdist < av_fac*avdist_init && + (double)num2_in > in_fac*(double)num2_in_init && + (double)num_in > in_fac*(double)num_in_init)) + { + // Replace surface + for (size_t kj=0; kj<reg.size(); ++kj) + { + reg[kj]->updateSurfaceAndInfo(elem2, approx_tol_, angtol, + parvals[kj], dist_ang[kj], + nopar_edgs); + } + } + for (size_t kj=0; kj<reg.size(); ++kj) + { + num_pts += reg[kj]->numPoints(); + double dom[4]; + reg[kj]->getDomain(dom); + udomain[0] = std::min(udomain[0], dom[0]); + udomain[1] = std::max(udomain[1], dom[1]); + } + int stop_break = 1; + } + + double seclim = 0.125*M_PI; + if (num_pts < min_point_region_ && udomain[1]-udomain[0] < seclim) + return dummy_loc; + return loc; +} + + +//=========================================================================== +void RevEng::collectAxis(vector<SurfaceProperties>& sfprop) +//=========================================================================== +{ + for (size_t ki=0; ki<surfaces_.size(); ++ki) + { + int code; + ClassType type = surfaces_[ki]->instanceType(code); + ClassType type2 = Class_Unknown; + shared_ptr<ParamSurface> surf = surfaces_[ki]->surface(); + shared_ptr<ElementarySurface> elemsf = + dynamic_pointer_cast<ElementarySurface,ParamSurface>(surf); + + RevEngRegion *reg0 = surfaces_[ki]->getRegion(0); + if (!reg0) + continue; // Surface should have been remove prior to this!!! + + if (reg0->hasBlendEdge()) + continue; // Derived information + + if (reg0->hasAssociatedBlend()) + continue; // Outdated information + + int nreg = surfaces_[ki]->numRegions(); + int num_pts = 0; + shared_ptr<ParamSurface> primary; +; + int num_pt_primary = 0; + bool prefer_base = false; // Maybe check accuracy between surface + // and primary surface later. Can also use history information about + // surface updates + bool type_cyl = (type == Class_Cylinder || type == Class_Cone); + int surfflag = 0; + for (int ka=0; ka<nreg; ++ka) + { + RevEngRegion *reg = surfaces_[ki]->getRegion(ka); + primary = reg->getBase(); + int num = reg->numPoints(); + num_pts += num; + double maxd, avd; + int num_in, num2_in; + reg->getAccuracy(maxd, avd, num_in, num2_in); + int surfflag0 = reg->defineSfFlag(num, 0, approx_tol_, num2_in, + num2_in, avd, type_cyl); + surfflag = std::max(surfflag, surfflag0); + vector<shared_ptr<ElementarySurface> > sfs(primary.get() ? 2: 1); + sfs[0] = elemsf; + if (primary.get()) + sfs[1] = dynamic_pointer_cast<ElementarySurface,ParamSurface>(primary); + double maxd2, avd2; + int num_in2, num2_in2, surfflag2; + int ix = reg->checkSurfaceAccuracy(sfs, approx_tol_, 5.0*anglim_, maxd2, + avd2, num_in2, num2_in2, surfflag2); + + if (reg->hasBaseSf() && num > num_pt_primary) + { + double maxdp, avdp; + int num_inp, num2_inp; + reg->getBaseDist(maxdp, avdp, num_inp, num2_inp); + if (num_inp > num/2 && avdp < approx_tol_) + { + num_pt_primary = num; + } + } + } + if (primary.get()) + type2 = primary->instanceType(); + + if ((!elemsf.get()) || prefer_base) + { + if (primary.get()) + elemsf = + dynamic_pointer_cast<ElementarySurface,ParamSurface>(primary); + } + if (!elemsf.get()) + continue; + + Point loc, dir; + double rad1, rad2; + loc = elemsf->location(); + dir = elemsf->direction(); + rad1 = elemsf->radius(0.0, 0.0); // Not good enough for cones + rad2 = elemsf->radius2(0.0, 0.0); // Not good enough for cones + SurfaceProperties currprop((int)ki, type, num_pts, surfflag, dir, loc, + type2, rad1, rad2); + sfprop.push_back(currprop); + } +} + + +//=========================================================================== +void RevEng::trimSurfaces() +//=========================================================================== +{ + double angtol = 5.0*anglim_; +#ifdef DEBUG_TRIM + std::ofstream of0("trimmedsfs.g2"); +#endif + // Missing edges between surfaces + size_t num_edg = edges_.size(); + recognizeEdges(true); + + vector<RevEngRegion*> out_regs; + vector<HedgeSurface*> out_sfs; + for (size_t kj=0; kj<edges_.size(); ++kj) + { + int type = edges_[kj]->getType(); + if (type == NOT_BLEND) + edges_[kj]->setTrimCurves(approx_tol_, angtol, out_regs, out_sfs); + } + if (out_regs.size() > 0 || out_sfs.size() > 0) + { + int ix = -1; + updateRegionsAndSurfaces(ix, out_regs, out_sfs); + } +#ifdef DEBUG_TRIM + vector<shared_ptr<ftEdge> > trim_edgs1; + for (size_t kr=0; kr<regions_.size(); ++kr) + { + // if (regions_[kr]->numPoints() == 0) + // std::cout << "Finished set blend boundaries, empty region, ki=" << kr << ", region: " << regions_[kr].get() << std::endl; + int num = regions_[kr]->numTrimEdges(); + if (num > 0) + { + vector<shared_ptr<ftEdge> > curr_edgs = regions_[kr]->getTrimEdges(); + trim_edgs1.insert(trim_edgs1.end(), curr_edgs.begin(), curr_edgs.end()); + } + } + if (trim_edgs1.size() > 0) + { + std::ofstream oft1("trim_edges_1.g2"); + for (size_t kr=0; kr<trim_edgs1.size(); ++kr) + { + shared_ptr<ParamCurve> tmp = trim_edgs1[kr]->geomCurve(); + shared_ptr<CurveOnSurface> tmp2 = + dynamic_pointer_cast<CurveOnSurface,ParamCurve>(tmp); + shared_ptr<ParamCurve> tmp3 = tmp2->spaceCurve(); + tmp3->writeStandardHeader(oft1); + tmp3->write(oft1); + } + } +#endif + //#if 0 + for (size_t ki=0; ki<regions_.size(); ++ki) + { + if (!regions_[ki]->hasSurface()) + continue; +#ifdef DEBUG_TRIM + std::ofstream of("trimreg.g2"); + regions_[ki]->writeRegionPoints(of); +#endif + + if (regions_[ki]->numTrimEdges() == 0) + continue; + if (regions_[ki]->hasBlendEdge()) + continue; + regions_[ki]->extendBoundaries(mean_edge_len_, min_point_region_, + approx_tol_, angtol, mainaxis_); + } + //#endif +#ifdef DEBUG_TRIM + vector<shared_ptr<ftEdge> > trim_edgs2; + for (size_t kr=0; kr<regions_.size(); ++kr) + { + // if (regions_[kr]->numPoints() == 0) + // std::cout << "Finished set blend boundaries, empty region, ki=" << kr << ", region: " << regions_[kr].get() << std::endl; + int num = regions_[kr]->numTrimEdges(); + if (num > 0) + { + vector<shared_ptr<ftEdge> > curr_edgs = regions_[kr]->getTrimEdges(); + trim_edgs2.insert(trim_edgs2.end(), curr_edgs.begin(), curr_edgs.end()); + } + } + if (trim_edgs2.size() > 0) + { + std::ofstream oft2("trim_edges_2.g2"); + for (size_t kr=0; kr<trim_edgs2.size(); ++kr) + { + shared_ptr<ParamCurve> tmp = trim_edgs2[kr]->geomCurve(); + shared_ptr<CurveOnSurface> tmp2 = + dynamic_pointer_cast<CurveOnSurface,ParamCurve>(tmp); + shared_ptr<ParamCurve> tmp3 = tmp2->spaceCurve(); + tmp3->writeStandardHeader(oft2); + tmp3->write(oft2); + } + } +#endif + + for (size_t ki=0; ki<regions_.size(); ++ki) + { + bool trimmed; + if (!regions_[ki]->hasSurface()) + continue; +#ifdef DEBUG_TRIM + std::ofstream of2("trimreg2.g2"); + regions_[ki]->writeRegionPoints(of2); +#endif + if (regions_[ki]->numTrimEdges() == 0) + { + trimmed = true; + regions_[ki]->getSurface(0)->trimWithPoints(approx_tol_); + } + else + { + try { + trimmed = regions_[ki]->trimSurface(approx_tol_); + } + catch (...) + { + trimmed = regions_[ki]->getSurface(0)->trimWithPoints(approx_tol_); +#ifdef DEBUG_TRIM + std::cout << ki << " trim with points " << std::endl; +#endif + } + if (!trimmed) + { + trimmed = regions_[ki]->getSurface(0)->trimWithPoints(approx_tol_); +#ifdef DEBUG_TRIM + std::cout << ki << " trim with points " << std::endl; +#endif + } + } + +#ifdef DEBUG_TRIM + if (trimmed) + { + shared_ptr<ParamSurface> tsurf = regions_[ki]->getSurface(0)->surface(); + shared_ptr<BoundedSurface> bdsurf = dynamic_pointer_cast<BoundedSurface,ParamSurface>(tsurf); + if (bdsurf.get()) + { + int valid_state; + bool valid = bdsurf->isValid(valid_state); + std::cout << "BoundedSurf " << ki << " is valid? " << valid << " " << valid_state << std::endl; + } + tsurf->writeStandardHeader(of2); + tsurf->write(of2); + } +#endif + + } +#ifdef DEBUG + std::cout << "Finished trim surf, regions: " << regions_.size() << ", surfaces: " << surfaces_.size() << std::endl; + if (regions_.size() > 0) + { + std::cout << "Regions13" << std::endl; + std::ofstream of("regions13.g2"); + std::ofstream ofm("mid_regions13.g2"); + std::ofstream ofs("small_regions13.g2"); + writeRegionStage(of, ofm, ofs); + std::ofstream of0("regions13_helix.g2"); + for (int ki=0; ki<(int)regions_.size(); ++ki) + { + if (regions_[ki]->getSurfaceFlag() == PROBABLE_HELIX) + { + regions_[ki]->writeRegionInfo(of0); + if (regions_[ki]->hasSurface()) + regions_[ki]->writeSurface(of0); + } + } + if (surfaces_.size() > 0) + { + std::ofstream of("regsurf13.g2"); + writeRegionWithSurf(of); + } + } + + if (edges_.size() > 0) + { + std::ofstream ofe("edges13.g2"); + writeEdgeStage(ofe); + } +#endif + +#if 0 +#ifdef DEBUG + std::ofstream of1("surfbd.g2"); +#endif + for (size_t ki=0; ki<surfaces_.size(); ++ki) + { + // Restrict unbounded surfaces + surfaces_[ki]->ensureSurfaceBounded(); +#ifdef DEBUG + surfaces_[ki]->surface()->writeStandardHeader(of1); + surfaces_[ki]->surface()->write(of1); +#endif + } + +#ifdef DEBUG + std::ofstream of3("trimsurfs.g2"); +#endif + for (size_t ki=0; ki<surfaces_.size(); ++ki) + { + surfaces_[ki]->trimWithPoints(approx_tol_); + +#ifdef DEBUG + surfaces_[ki]->surface()->writeStandardHeader(of3); + surfaces_[ki]->surface()->write(of3); +#endif + int stop1 = 1; + } +#endif + int stop_break = 1; +} + + //=========================================================================== +shared_ptr<SurfaceModel> RevEng::createModel() +//=========================================================================== +{ + // Ensure bounded surfaces + for (size_t ki=0; ki<surfaces_.size(); ++ki) + { + shared_ptr<ParamSurface> surf = surfaces_[ki]->surface(); + if (!surf->isBounded()) + { + RevEngRegion *reg = surfaces_[ki]->getRegion(0); + double dom[4]; + reg->getDomain(dom); + shared_ptr<Plane> plane = dynamic_pointer_cast<Plane,ParamSurface>(surf); + shared_ptr<Cylinder> cyl = dynamic_pointer_cast<Cylinder,ParamSurface>(surf); + shared_ptr<Cone> cone = dynamic_pointer_cast<Cone,ParamSurface>(surf); + if (plane.get()) + plane->setParameterBounds(dom[0], dom[2], dom[1], dom[3]); + else if (cyl.get()) + cyl->setParamBoundsV(dom[2], dom[3]); + else if (cone.get()) + cone->setParamBoundsV(dom[2], dom[3]); + } + } + + double gap_tol = std::max(10.0*int_tol_, 0.01*approx_tol_); + vector<shared_ptr<ftSurface> > tmpsfs(surfaces_.begin(), surfaces_.end()); + sfmodel_ = shared_ptr<SurfaceModel>(new SurfaceModel(approx_tol_, gap_tol, + 10*gap_tol, anglim_, 10*anglim_, + tmpsfs)); +#ifdef DEBUG_MODEL + int num_bd = sfmodel_->nmbBoundaries(); + if (num_bd > 0) + { + std::ofstream of1("model_boundaries.g2"); + for (int ka=0; ka<num_bd; ++ka) + { + ftCurve bd = sfmodel_->getBoundary(ka); + int num_seg = bd.numSegments(); + for (int kb=0; kb<num_seg; ++kb) + { + shared_ptr<ParamCurve> cv = bd.segment(kb).spaceCurve(); + cv->writeStandardHeader(of1); + cv->write(of1); + } + } + } + +#endif + return sfmodel_; +} + + //=========================================================================== +void RevEng::initParameters() +//=========================================================================== +{ + // Set default parameters + min_next_ = 10; // Minimum number of neighbouring points + max_next_ = 500; //std::min(80, tri_sf_->size()/200); //500; + rfac_ = 6.0; //3.0; // Factor for radius in which to search for neighbouring points + cfac_ = 8.0; // Edge points from curvature is given by + // cfac_ times the average length of triangulation edges in a vertex + norm_plane_lim_= 0.005; // Limit for when the cone angle corresponding + // to triangle normals indicate an edge + zero_H_ = 0.005; //0.001; //0.0001; // When mean curvature is considered zero + zero_K_ = 0.005; //0.001; //0.0001; // When Gauss curvature is considered zero + norm_ang_lim_ = 0.1*M_PI; // Limit for when the cone angle corresponding + // to triangle normals indicate an edge + min_point_region_ = 200; //50; //10; // Should be updated with regard to the total + // number of points + approx_tol_ = 0.001; // Very preliminary + int_tol_ = 1.0e-6; + anglim_ = 0.01; + max_nmb_outlier_ = 3; + + model_character_ = 2; + prefer_elementary_ = 0; + mainaxis_[0] = Point(1.0, 0.0, 0.0); + mainaxis_[1] = Point(0.0, 1.0, 0.0); + mainaxis_[2] = Point(0.0, 0.0, 1.0); +} + + //=========================================================================== +void RevEng::updateParameters() +//=========================================================================== +{ + if (model_character_ == SMOOTH) + { + rfac_ = 4.0; + } + else if (model_character_ == MEDIUM_ROUGH) + { + zero_H_ = 0.007; + zero_K_ = 0.007; + } + else + { + rfac_ = 6.0; + zero_H_ = 0.01; + zero_K_ = 0.01; + anglim_ = 0.02; + } +} + + //=========================================================================== +int RevEng::setSmallRegionNumber() +//=========================================================================== +{ + vector<int> nmb_pt_reg(regions_.size()); + for (size_t ki=0; ki<regions_.size(); ++ki) + nmb_pt_reg[ki] = regions_[ki]->numPoints(); + + std::sort(nmb_pt_reg.begin(), nmb_pt_reg.end()); + int tot_num = tri_sf_->size(); + int num_reg = (int)regions_.size(); + int idel = tot_num/num_reg; + int min_num = std::min(10, tot_num/20); + int ixmax = (int)(0.99*num_reg); + int Q4 = 3*num_reg/4; + int max_num = std::max(min_num, nmb_pt_reg[ixmax]); + int Q4_num = nmb_pt_reg[Q4]; + max_num = std::min(max_num, 10*idel); + int ixdel = std::max(num_reg/100, 2); + int prev = nmb_pt_reg[0], prev0 = 0; + int ix; + int fac = 2; + int min_jump = std::min(idel, Q4_num); //2; + for (ix=ixdel; ix<num_reg; ix+=ixdel) + { + int diff = nmb_pt_reg[ix] - prev; + if (diff > fac*(std::max(min_jump, prev-prev0))) + break; + if (diff > 0) + prev0 = prev; + prev = nmb_pt_reg[ix]; + } + ix = std::min(ix, ixmax); + + int num = std::max(min_num, std::min(nmb_pt_reg[ix], max_num/2)); + return num; +} + + + //=========================================================================== +void RevEng::checkConsistence(std::string text) const +//=========================================================================== +{ + for (int ki=0; ki<(int)regions_.size(); ++ki) + { + vector<RevEngRegion*> adjacent; + regions_[ki]->getAdjacentRegions(adjacent); + for (size_t kj=0; kj<adjacent.size(); ++kj) + { + size_t kr; + for (kr=0; kr<regions_.size(); ++kr) + if (adjacent[kj] == regions_[kr].get()) + break; + if (kr == regions_.size()) + std::cout << text << ", Obsolete region pointer, ki=" << ki << ", kj=" << kj << ". Region: " << adjacent[kj] << std::endl; + } + } + for (int ki=0; ki<(int)surfaces_.size(); ++ki) + { + int numreg = surfaces_[ki]->numRegions(); + for (int ka=0; ka<numreg; ++ka) + { + RevEngRegion *reg = surfaces_[ki]->getRegion(ka); + size_t kr; + for (kr=0; kr<regions_.size(); ++kr) + if (reg == regions_[kr].get()) + break; + if (kr == regions_.size()) + std::cout << text << ", surface 1. Obsolete region pointer, ki=" << ki << ", ka=" << ka << ". Region: " << reg << std::endl; + vector<RevEngRegion*> adjacent; + reg->getAdjacentRegions(adjacent); + for (size_t kj=0; kj<adjacent.size(); ++kj) + { + size_t kr; + for (kr=0; kr<regions_.size(); ++kr) + if (adjacent[kj] == regions_[kr].get()) + break; + if (kr == regions_.size()) + std::cout << text << ", surface. Obsolete region pointer, ki=" << ki << ", kj=" << kj << ". Region: " << adjacent[kj] << std::endl; + } + } + } +} + + //=========================================================================== +void RevEng::storeClassified(ostream& os) const +//=========================================================================== +{ + storeParams(os); + int nmbpts = tri_sf_->size(); + os << nmbpts << std::endl; + for (int ki=0; ki<nmbpts; ++ki) + { + RevEngPoint *pt = dynamic_cast<RevEngPoint*>((*tri_sf_)[ki]); + pt->store(os); + } +} + + //=========================================================================== +void RevEng::readClassified(istream& is) +//=========================================================================== +{ + readParams(is); + int nmbpts; + is >> nmbpts; + tri_sf_ = shared_ptr<ftPointSet>(new ftPointSet()); + vector<vector<int> > next_ix(nmbpts); + for (int ki=0; ki<nmbpts; ++ki) + { + shared_ptr<RevEngPoint> vertex(new RevEngPoint()); + vertex->read(is, next_ix[ki]); + tri_sf_->addEntry(vertex); + } + + // Add next information + for (int ki=0; ki<nmbpts; ++ki) + { + ftSamplePoint* pt1 = (*tri_sf_)[ki]; + for (size_t kr=0; kr<next_ix[ki].size(); ++kr) + { + int ix = next_ix[ki][kr]; + ftSamplePoint* pt2 = (*tri_sf_)[ix]; + pt1->addNeighbour(pt2); + } + } + + max_next_ = std::min(80, tri_sf_->size()/200); + max_next_ = std::max(2*min_next_, max_next_); + setBoundingBox(); +} + + //=========================================================================== +void RevEng::storeGrownRegions(ostream& os) +//=========================================================================== +{ + storeClassified(os); + os << surfaces_.size() << std::endl; + for (int ka=0; ka<(int)surfaces_.size(); ++ka) + { + surfaces_[ka]->setId(ka); + surfaces_[ka]->store(os); + } + os << regions_.size() << std::endl; + for (size_t ki=0; ki<regions_.size(); ++ki) + { + regions_[ki]->setId((int)ki); + regions_[ki]->store(os); + } + + os << single_points_.size() << std::endl; + for (size_t ki=0; ki<single_points_.size(); ++ki) + os << single_points_[ki]->getIndex() << " "; + os << std::endl; + + os << edges_.size() << std::endl; + for (int ka=0; ka<(int)edges_.size(); ++ka) + { + edges_[ka]->setId(ka); + edges_[ka]->store(os); + } + + os << model_axis_.size() << std::endl; + for (size_t ki=0; ki<model_axis_.size(); ++ki) + { + os << model_axis_[ki].axis_ << " " << model_axis_[ki].plane_loc_.size(); + os << " " << model_axis_[ki].rotational_loc_.size() << std::endl; + for (size_t kj=0; kj<model_axis_[ki].plane_loc_.size(); ++kj) + { + os << model_axis_[ki].plane_loc_[kj].first << " "; + os << model_axis_[ki].plane_loc_[kj].second << " "; + } + os << std::endl; + for (size_t kj=0; kj<model_axis_[ki].rotational_loc_.size(); ++kj) + { + os << model_axis_[ki].rotational_loc_[kj].first << " "; + os << model_axis_[ki].rotational_loc_[kj].second << " "; + } + os << std::endl; + } + +} + + //=========================================================================== +void RevEng::readGrownRegions(istream& is) +//=========================================================================== +{ + readClassified(is); + int nmb = tri_sf_->size(); + vector<ftSamplePoint*> tmp_pts(nmb); + for (int ka=0; ka<nmb; ++ka) + tmp_pts[ka] = (*tri_sf_)[ka]; + std::set<ftSamplePoint*> tmp_set(tmp_pts.begin(), tmp_pts.end()); + std::cout << "Read grown, size1 = " << tmp_pts.size() << ", size2 = " << tmp_set.size() << std::endl; + curvatureFilter(); + int num_sfs; + is >> num_sfs; + if (num_sfs > 0) + surfaces_.resize(num_sfs); + for (int ki=0; ki<num_sfs; ++ki) + { + surfaces_[ki] = shared_ptr<HedgeSurface>(new HedgeSurface()); + surfaces_[ki]->read(is); + } + + int num_regions; + is >> num_regions; + regions_.resize(num_regions); + for (int ki=0; ki<num_regions; ++ki) + { + vector<int> sf_id; + regions_[ki] = shared_ptr<RevEngRegion>(new RevEngRegion(edge_class_type_)); + regions_[ki]->read(is, tri_sf_, sf_id); + for (size_t kj=0; kj<sf_id.size(); ++kj) + { + for (size_t kr=0; kr<surfaces_.size(); ++kr) + { + if (sf_id[kj] == surfaces_[kr]->getId()) + { + regions_[ki]->addHedge(surfaces_[kr].get()); + surfaces_[kr]->addRegion(regions_[ki].get()); + break; + } + } + } + } + + for (int ki=0; ki<num_regions; ++ki) + { + regions_[ki]->setRegionAdjacency(); + } + + int num_single; + is >> num_single; + single_points_.resize(num_single); + for (int ki=0; ki<num_single; ++ki) + { + int ix; + is >> ix; + RevEngPoint* pt = dynamic_cast<RevEngPoint*>((*tri_sf_)[ix]); + single_points_[ki] = pt; + } + + int num_edgs; + is >> num_edgs; + if (num_edgs > 0) + edges_.resize(num_edgs); + for (int ki=0; ki<num_edgs; ++ki) + { + edges_[ki] = shared_ptr<RevEngEdge>(new RevEngEdge()); + int id1, id2, id3; + vector<int> blend_id; + edges_[ki]->read(is, id1, id2, id3, blend_id); + + for (size_t kr=0; kr<regions_.size(); ++kr) + { + int id = regions_[kr]->getId(); + if (id == id1) + { + edges_[ki]->setReg1(regions_[kr].get()); + regions_[kr]->addRevEdge(edges_[ki].get()); + break; + } + } + + for (size_t kr=0; kr<regions_.size(); ++kr) + { + int id = regions_[kr]->getId(); + if (id == id2) + { + edges_[ki]->setReg2(regions_[kr].get()); + regions_[kr]->addRevEdge(edges_[ki].get()); + break; + } + } + + if (id3 >= 0) + { + for (size_t kr=0; kr<regions_.size(); ++kr) + { + int id = regions_[kr]->getId(); + if (id == id3) + { + edges_[ki]->setBlendRegSurf(regions_[kr].get()); + regions_[kr]->setBlendEdge(edges_[ki].get()); + break; + } + } + } + + for (size_t kh=0; kh<blend_id.size(); ++kh) + { + for (size_t kr=0; kr<regions_.size(); ++kr) + { + int id = regions_[kr]->getId(); + if (blend_id[kh] == id) + { + edges_[ki]->addBlendRegion(regions_[kr].get()); + regions_[kr]->setAssociatedBlend(edges_[ki].get()); + break; + } + } + } + } + + int num_axis; + is >> num_axis; + for (int ki=0; ki<num_axis; ++ki) + { + Point axis(3); + int num_planar, num_rotational; + is >> axis[0] >> axis[1] >> axis[2] >> num_planar >> num_rotational; + model_axis_.push_back(AxisInfo(axis)); + for (int kj=0; kj<num_planar; ++kj) + { + Point loc(3); + int num; + is >> loc[0] >> loc[1] >> loc[2] >> num; + model_axis_[ki].addPlaneLocation(loc, num); + } + for (int kj=0; kj<num_rotational; ++kj) + { + Point loc(3); + int num; + is >> loc[0] >> loc[1] >> loc[2] >> num; + model_axis_[ki].addRotationalLocation(loc, num); + } + } + int stop_break = 1; +} + + + //=========================================================================== +void RevEng::storeParams(ostream& os) const +//=========================================================================== +{ + os << model_character_ << " " << mean_edge_len_ << " " << min_next_; + os << " " << norm_ang_lim_; + os << " " << norm_plane_lim_ << " " << zero_H_ << " " << zero_K_; + os << " " << min_point_region_ << " " << approx_tol_ ; + os << " " << anglim_ << " " << max_nmb_outlier_ << " "; + os << edge_class_type_ << " " << classification_type_ << std::endl; + os << mainaxis_[0] << " " << mainaxis_[1] << " " << mainaxis_[2] << std::endl; +} + + //=========================================================================== +void RevEng::readParams(istream& is) +//=========================================================================== +{ + is >> model_character_ >> mean_edge_len_ >> min_next_; + is >> norm_ang_lim_ >> norm_plane_lim_ >> zero_H_ >> zero_K_; + is >> min_point_region_ >> approx_tol_ >> anglim_ >> max_nmb_outlier_; + is >> edge_class_type_ >> classification_type_; + mainaxis_[0].resize(3); + mainaxis_[1].resize(3); + mainaxis_[2].resize(3); + is >> mainaxis_[0] >> mainaxis_[1] >> mainaxis_[2]; +} + +//=========================================================================== +void RevEng::writeRegionWithSurf(ostream& of) const +//=========================================================================== +{ + for (size_t kr=0; kr<surfaces_.size(); ++kr) + { + int numreg = surfaces_[kr]->numRegions(); + if (numreg > 0) + { + RevEngRegion *reg = surfaces_[kr]->getRegion(0); + reg->writeRegionPoints(of); + reg->writeSurface(of); + } + else + { + double diag = bbox_.low().dist(bbox_.high()); + surfaces_[kr]->limitSurf(diag); + surfaces_[kr]->surface()->writeStandardHeader(of); + surfaces_[kr]->surface()->write(of); + } + } +} + + //=========================================================================== +void RevEng::writeRegionStage(ostream& of, ostream& ofm, ostream& ofs) const +//=========================================================================== +{ + std::cout << "Num regions: " << regions_.size() << ", num surfaces: " << surfaces_.size() << " num edges: " << edges_.size() << std::endl; + + vector<Vector3D> small; + int nmb_one = 0; + int low = min_point_region_/10; + for (size_t kr=0; kr<regions_.size(); ++kr) + { + // BoundingBox bbox = regions_[kr]->boundingBox(); + // if (bbox.low().dist(bbox.high()) < 0.1) + // std::cout << "Small bounding box" << std::endl; + // std::set<RevEngPoint*> tmpset(regions_[kr]->pointsBegin(), regions_[kr]->pointsEnd()); + // if (tmpset.size() != regions_[kr]->numPoints()) + // std::cout << "Point number mismatch. " << kr << " " << tmpset.size() << " " << regions_[kr]->numPoints() << std::endl; + int nmb = regions_[kr]->numPoints(); + if (nmb < low && regions_[kr]->hasSurface() == false) + { + for (int ki=0; ki<nmb; ++ki) + small.push_back(regions_[kr]->getPoint(ki)->getPoint()); + } + else if (nmb < min_point_region_ && regions_[kr]->hasSurface() == false) + { + ofm << "400 1 0 0" << std::endl; + ofm << nmb << std::endl; + for (int ki=0; ki<nmb; ++ki) + { + ofm << regions_[kr]->getPoint(ki)->getPoint() << std::endl; + } + if (regions_[kr]->hasSurface()) + regions_[kr]->writeSurface(ofm); + } + else + { + if (nmb > 0) + { + of << "400 1 0 0" << std::endl; + of << nmb << std::endl; + for (int ki=0; ki<nmb; ++ki) + { + of << regions_[kr]->getPoint(ki)->getPoint() << std::endl; + } + } + if (regions_[kr]->hasSurface()) + regions_[kr]->writeSurface(of); + } + if (nmb == 1) + nmb_one++; + } + std::cout << "Number of regions with one point: " << nmb_one << std::endl; + ofs << "400 1 0 4 0 0 0 255" << std::endl; + ofs << small.size() << std::endl; + for (size_t kr=0; kr<small.size(); ++kr) + ofs << small[kr] << std::endl; +} + +//=========================================================================== +void RevEng::writeEdgeStage(ostream& of) const +//=========================================================================== +{ + for (size_t kr=0; kr<edges_.size(); ++kr) + { + vector<shared_ptr<ParamCurve> > cvs = edges_[kr]->getSpaceCurves(); + for (size_t kh=0; kh<cvs.size(); ++kh) + { + cvs[kh]->writeStandardHeader(of); + cvs[kh]->write(of); + } + int num_blend = edges_[kr]->numBlendRegs(); + for (int ka=0; ka<num_blend; ++ka) + edges_[kr]->getBlendReg(ka)->writeRegionPoints(of); + } +} diff --git a/compositemodel/src/RevEngEdge.C b/compositemodel/src/RevEngEdge.C new file mode 100644 index 00000000..7a550f75 --- /dev/null +++ b/compositemodel/src/RevEngEdge.C @@ -0,0 +1,1626 @@ +/* + * Copyright (C) 1998, 2000-2007, 2010, 2011, 2012, 2013 SINTEF ICT, + * Applied Mathematics, Norway. + * + * Contact information: E-mail: tor.dokken@sintef.no + * SINTEF ICT, Department of Applied Mathematics, + * P.O. Box 124 Blindern, + * 0314 Oslo, Norway. + * + * This file is part of GoTools. + * + * GoTools is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * GoTools 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with GoTools. If not, see + * <http://www.gnu.org/licenses/>. + * + * In accordance with Section 7(b) of the GNU Affero General Public + * License, a covered work must retain the producer line in every data + * file that is created or manipulated using GoTools. + * + * Other Usage + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial activities involving the GoTools library without + * disclosing the source code of your own applications. + * + * This file may be used in accordance with the terms contained in a + * written agreement between you and SINTEF ICT. + */ + +#include "GoTools/compositemodel/RevEngEdge.h" +#include "GoTools/compositemodel/HedgeSurface.h" +#include "GoTools/compositemodel/ftEdge.h" +#include "GoTools/geometry/Factory.h" +#include "GoTools/geometry/GoTools.h" +#include "GoTools/geometry/ObjectHeader.h" +#include "GoTools/geometry/SurfaceTools.h" +#include "GoTools/geometry/ClosestPoint.h" +#include "GoTools/geometry/BoundedUtils.h" +#include "GoTools/intersections/Identity.h" +#include <fstream> + +//#define DEBUG +//#define DEBUG_BLEND + +using namespace Go; +using std::vector; +using std::istream; +using std::ostream; + +//=========================================================================== +RevEngEdge::RevEngEdge() +//=========================================================================== + : adjacent1_(0), adjacent2_(0), defined_blend_(0), + blend_type_(BLEND_NOT_SET), outer1_(false), outer2_(false), + distance_(0.0), radius_(0.0), surfchangecount_(0), extendcount_(0) +{ +} + +//=========================================================================== +RevEngEdge::RevEngEdge(RevEngRegion* reg1, RevEngRegion* reg2) +//=========================================================================== + : adjacent1_(reg1), adjacent2_(reg2), defined_blend_(0), + blend_type_(BLEND_NOT_SET), outer1_(false), outer2_(false), + distance_(0.0), radius_(0.0), surfchangecount_(0), extendcount_(0) +{ +} + +//=========================================================================== +RevEngEdge::RevEngEdge(int type, RevEngRegion* reg1, + vector<shared_ptr<CurveOnSurface> > cvs1, + bool out1, RevEngRegion* reg2, + vector<shared_ptr<CurveOnSurface> > cvs2, + bool out2, double distance, double radius) +//=========================================================================== + : adjacent1_(reg1), adjacent2_(reg2), defined_blend_(0), blend_type_(type), + outer1_(out1), outer2_(out2), distance_(distance), radius_(radius), + surfchangecount_(0), extendcount_(0) +{ + cvs1_.insert(cvs1_.end(), cvs1.begin(), cvs1.end()); + cvs2_.insert(cvs2_.end(), cvs2.begin(), cvs2.end()); +} + +//=========================================================================== +RevEngEdge::~RevEngEdge() +//=========================================================================== +{ + if (adjacent1_) + adjacent1_->removeRevEngEdge(this); + if (adjacent2_) + adjacent2_->removeRevEngEdge(this); + for (size_t ki=0; ki<blend_regs_.size(); ++ki) + blend_regs_[ki]->removeAssociatedBlend(); + if (defined_blend_) + defined_blend_->removeBlendEdge(); +} + + +//=========================================================================== +void RevEngEdge::setReg1(RevEngRegion *reg) +//=========================================================================== +{ + adjacent1_ = reg; + shared_ptr<ParamSurface> surf; + if (reg->hasSurface()) + surf = reg->getSurface(0)->surface(); + else if (reg->hasBaseSf()) + surf = reg->getBase(); + + if (surf.get()) + { + for (size_t ki=0; ki<cvs1_.size(); ++ki) + cvs1_[ki]->setUnderlyingSurface(surf); + } +} + +//=========================================================================== +void RevEngEdge::setReg2(RevEngRegion *reg) +//=========================================================================== +{ + adjacent2_ = reg; + shared_ptr<ParamSurface> surf; + if (reg->hasSurface()) + surf = reg->getSurface(0)->surface(); + else if (reg->hasBaseSf()) + surf = reg->getBase(); + + if (surf.get()) + { + for (size_t ki=0; ki<cvs2_.size(); ++ki) + cvs2_[ki]->setUnderlyingSurface(surf); + } +} + +//=========================================================================== +void RevEngEdge::fixMismatchCurves(double tol) +//=========================================================================== +{ + for (size_t ki=0; ki<cvs1_.size(); ++ki) + cvs1_[ki]->fixMismatchCurves(tol); + for (size_t ki=0; ki<cvs2_.size(); ++ki) + cvs2_[ki]->fixMismatchCurves(tol); +} + +//=========================================================================== +void RevEngEdge::replaceSurf(RevEngRegion* reg, + shared_ptr<ParamSurface>& new_surf, double tol) +//=========================================================================== +{ + if (reg == adjacent1_) + { + for (size_t ki=0; ki<cvs1_.size(); ++ki) + { + cvs1_[ki]->setUnderlyingSurface(new_surf); + cvs1_[ki]->unsetParameterCurve(); + cvs1_[ki]->ensureParCrvExistence(tol); +#ifdef DEBUG + if (!cvs1_[ki]->hasParameterCurve()) + std::cout << "RevEngEdge::replaceSurf: No parameter curve" << std::endl; +#endif + } + } + else if (reg == adjacent2_) + { + for (size_t ki=0; ki<cvs2_.size(); ++ki) + { + cvs2_[ki]->setUnderlyingSurface(new_surf); + cvs2_[ki]->unsetParameterCurve(); + cvs2_[ki]->ensureParCrvExistence(tol); +#ifdef DEBUG + if (!cvs2_[ki]->hasParameterCurve()) + std::cout << "RevEngEdge::replaceSurf: No parameter curve" << std::endl; +#endif + } + } + +} + +//=========================================================================== +void RevEngEdge::store(ostream& os) +//=========================================================================== +{ + os << Id_ << std::endl; + int id1 = (adjacent1_) ? adjacent1_->getId() : -1; + int id2 = (adjacent2_) ? adjacent2_->getId() : -1; + int id3 = (defined_blend_ == 0) ? -1 : defined_blend_->getId(); + os << id1 << " " << id2 << " " << id3 << std::endl; + os << cvs1_.size() << " " << cvs2_.size() << std::endl; + + for (size_t ki=0; ki<cvs1_.size(); ++ki) + { + cvs1_[ki]->write(os); + // bool space = cvs1_[ki]->hasSpaceCurve(); + // bool param = cvs1_[ki]->hasParameterCurve(); + // os << space << " " << param << std::endl; + // if (space) + // { + // shared_ptr<ParamCurve> spacecv = cvs1_[ki]->spaceCurve(); + // shared_ptr<ParamCurve> parcv = cvs1_[ki]->parameterCurve(); + // spacecv->writeStandardHeader(os); + // spacecv->write(os); + // parcv->writeStandardHeader(os); + // parcv->write(os); + // } + } + + for (size_t ki=0; ki<cvs2_.size(); ++ki) + { + cvs2_[ki]->write(os); + // bool space = cvs2_[ki]->hasSpaceCurve(); + // bool param = cvs2_[ki]->hasParameterCurve(); + // os << space << " " << param << std::endl; + // if (space) + // { + // shared_ptr<ParamCurve> spacecv = cvs2_[ki]->spaceCurve(); + // shared_ptr<ParamCurve> parcv = cvs2_[ki]->parameterCurve(); + // spacecv->writeStandardHeader(os); + // spacecv->write(os); + // parcv->writeStandardHeader(os); + // parcv->write(os); + // } + } + + os << blend_regs_.size() << std::endl; + for (size_t ki=0; ki < blend_regs_.size(); ++ki) + os << blend_regs_[ki]->getId() << " "; + os << std::endl; + + os << blend_type_ << " " << distance_ << " " << radius_ << " "; + os << outer1_ << " " << outer2_ << " "; + os << surfchangecount_ << " " << extendcount_ << std::endl; +} + + +//=========================================================================== +void RevEngEdge::read(istream& is, int& reg_id1, int& reg_id2, int& reg_id3, + vector<int>& blend_id) +//=========================================================================== +{ + is >> Id_; + is >> reg_id1 >> reg_id2 >> reg_id3; + int num_cv1, num_cv2; + is >> num_cv1 >> num_cv2; + if (num_cv1 > 0) + cvs1_.resize(num_cv1); + if (num_cv2 > 0) + cvs2_.resize(num_cv2); + for (int ka=0; ka<num_cv1; ++ka) + { + cvs1_[ka] = shared_ptr<CurveOnSurface>(new CurveOnSurface()); + cvs1_[ka]->read(is); + // int space, param; + // is >> space >> param; + // shared_ptr<ParamCurve> spacecv, parcv; + // shared_ptr<ParamSurface> dummy; + // if (space) + // { + // ObjectHeader header; + // header.read(is); + // shared_ptr<GeomObject> obj(Factory::createObject(header.classType())); + // obj->read(is); + // spacecv = dynamic_pointer_cast<ParamCurve,GeomObject>(obj); + // } + + // if (param) + // { + // ObjectHeader header; + // header.read(is); + // shared_ptr<GeomObject> obj(Factory::createObject(header.classType())); + // obj->read(is); + // parcv = dynamic_pointer_cast<ParamCurve,GeomObject>(obj); + // } + + // cvs1_[ka] = shared_ptr<CurveOnSurface>(new CurveOnSurface(dummy, parcv, + // spacecv, false, + // -1, -1, 0.0, + // -1, true)); + } + + for (int ka=0; ka<num_cv2; ++ka) + { + cvs2_[ka] = shared_ptr<CurveOnSurface>(new CurveOnSurface()); + cvs2_[ka]->read(is); + // int space, param; + // is >> space >> param; + // shared_ptr<ParamCurve> spacecv, parcv; + // shared_ptr<ParamSurface> dummy; + // if (space) + // { + // ObjectHeader header; + // header.read(is); + // shared_ptr<GeomObject> obj(Factory::createObject(header.classType())); + // obj->read(is); + // spacecv = dynamic_pointer_cast<ParamCurve,GeomObject>(obj); + // } + + // if (param) + // { + // ObjectHeader header; + // header.read(is); + // shared_ptr<GeomObject> obj(Factory::createObject(header.classType())); + // obj->read(is); + // parcv = dynamic_pointer_cast<ParamCurve,GeomObject>(obj); + // } + + // cvs2_[ka] = shared_ptr<CurveOnSurface>(new CurveOnSurface(dummy, parcv, + // spacecv, false, + // -1, -1, 0.0, + // -1, true)); + } + + int num_blend_reg; + is >> num_blend_reg; + if (num_blend_reg > 0) + blend_id.resize(num_blend_reg); + for (int ka=0; ka<num_blend_reg; ++ka) + is >> blend_id[ka]; + + is >> blend_type_ >> distance_ >> radius_ >> outer1_ >> outer2_; + is >> surfchangecount_ >> extendcount_; +} + + +//=========================================================================== +vector<shared_ptr<ParamCurve> > RevEngEdge::getSpaceCurves() +//=========================================================================== +{ + vector<shared_ptr<ParamCurve> > curves; + for (size_t ki=0; ki<cvs1_.size(); ++ki) + curves.push_back(cvs1_[ki]->spaceCurve()); + + return curves; +} + +//=========================================================================== +void RevEngEdge::getCrvEndPoints(Point& pos1, Point& pos2) +//=========================================================================== +{ + if (cvs1_.size() > 0) + { + cvs1_[0]->point(pos1, cvs1_[0]->startparam()); + cvs1_[cvs1_.size()-1]->point(pos2, cvs1_[cvs1_.size()-1]->endparam()); + } +} + +//=========================================================================== +void RevEngEdge::closestPoint(const Point& pos, double& par, Point& close, + double& dist) +//=========================================================================== +{ + int ix; + closestPoint(pos, par, close, dist, ix); +} + +//=========================================================================== +void RevEngEdge::closestPoint(const Point& pos, double& par, Point& close, + double& dist, int& ix) +//=========================================================================== +{ + dist = std::numeric_limits<double>::max(); + ix = -1; + for (size_t ki=0; ki<cvs1_.size(); ++ki) + { + double par1, dist1; + Point close1; + cvs1_[ki]->closestPoint(pos, cvs1_[ki]->startparam(), + cvs1_[ki]->endparam(), par1, close1, dist1); + if (dist1 < dist) + { + par = par1; + close = close1; + dist = dist1; + ix = (int)ki; + } + } +} + +//=========================================================================== +int RevEngEdge::closedSfAtEnd(double tol, double& par, Point& pos, bool at_start) +//=========================================================================== +{ + if (cvs1_.size() == 0) + return 0; + + shared_ptr<ParamSurface> surf1 = cvs1_[0]->underlyingSurface(); + shared_ptr<ParamSurface> surf2 = cvs2_[0]->underlyingSurface(); + + // The parameter interval and the space curve of the two curve sequences + // correspond + int ix = (at_start) ? 0 : (int)cvs1_.size()-1; + par = (at_start) ? cvs1_[ix]->startparam() : cvs1_[ix]->endparam(); + pos = cvs1_[ix]->ParamCurve::point(par); + + double eps = 1.0e-9; + double u1, u2, v1, v2, d1, d2; + Point close1, close2; + surf1->closestBoundaryPoint(pos, u1, v1, close1, d1, eps); + surf2->closestBoundaryPoint(pos, u2, v2, close2, d2, eps); + if (d1 > tol && d2 > tol) + return 0; + + if (d1 <= tol) + { + RectDomain dom = surf1->containingDomain(); + if (fabs(u1-dom.umin()) <= eps) + { + Point pos2 = surf1->point(dom.umax(), v1); + if (pos.dist(pos2) <= tol) + return 1; + } + else if (fabs(dom.umax()-u1) <= eps) + { + Point pos2 = surf1->point(dom.umin(), v1); + if (pos.dist(pos2) <= tol) + return 1; + } + if (fabs(v1-dom.vmin()) <= eps) + { + Point pos2 = surf1->point(u1, dom.vmax()); + if (pos.dist(pos2) <= tol) + return 1; + } + else if (fabs(dom.vmax()-v1) <= eps) + { + Point pos2 = surf1->point(u1, dom.vmin()); + if (pos.dist(pos2) <= tol) + return 1; + } + } + + if (d2 <= tol) + { + RectDomain dom = surf2->containingDomain(); + if (fabs(u2-dom.umin()) <= eps) + { + Point pos2 = surf2->point(dom.umax(), v2); + if (pos.dist(pos2) <= tol) + return 2; + } + else if (fabs(dom.umax()-u2) <= eps) + { + Point pos2 = surf2->point(dom.umin(), v2); + if (pos.dist(pos2)) + return 2; + } + if (fabs(v2-dom.vmin()) <= eps) + { + Point pos2 = surf2->point(u2, dom.vmax()); + if (pos.dist(pos2) <= tol) + return 2; + } + else if (fabs(dom.vmax()-v2) <= eps) + { + Point pos2 = surf2->point(u2, dom.vmin()); + if (pos.dist(pos2) <= tol) + return 2; + } + } + + return 0; +} + +//=========================================================================== +bool RevEngEdge::isClosed(double tol) +//=========================================================================== +{ + if (cvs1_.size() == 0) + return false; + double par1 = cvs1_[0]->startparam(); + double par2 = cvs1_[cvs1_.size()-1]->endparam(); + Point pos1 = cvs1_[0]->ParamCurve::point(par1); + Point pos2 = cvs1_[cvs1_.size()-1]->ParamCurve::point(par2); + double dist = pos1.dist(pos2); + return (dist <= tol); +} + +//=========================================================================== +bool RevEngEdge::isAdjacent(RevEngEdge* other, double tol, double& par1, double& par2) +//=========================================================================== +{ + if (cvs1_.size() == 0) + return false; + double tpar1 = cvs1_[0]->startparam(); + double tpar2 = cvs1_[cvs1_.size()-1]->endparam(); + Point pos1 = cvs1_[0]->ParamCurve::point(tpar1); + Point pos2 = cvs1_[cvs1_.size()-1]->ParamCurve::point(tpar2); + double tpar3 = other->startparam(); + double tpar4 = other->endparam(); + Point pos3 = other->point(tpar3); + Point pos4 = other->point(tpar4); + + double dd1 = pos1.dist(pos3); + double dd2 = pos1.dist(pos4); + double dd3 = pos2.dist(pos3); + double dd4 = pos2.dist(pos4); + bool adjacent = false; + if (dd1 <= tol && dd1 <= std::min(dd2, std::min(dd3,dd4))) + { + par1 = tpar1; + par2 = tpar3; + adjacent = true; + } + else if (dd2 <= tol && dd2 <= std::min(dd3, dd4)) + { + par1 = tpar1; + par2 = tpar4; + adjacent = true; + } + else if (dd3 <= tol && dd3 <= dd4) + { + par1 = tpar2; + par2 = tpar3; + adjacent = true; + } + else if (dd4 <= tol) + { + par1 = tpar2; + par2 = tpar4; + adjacent = true; + } + return adjacent; +} + +//=========================================================================== +Point RevEngEdge::point(double par) +//=========================================================================== +{ + Point dummy; + if (cvs1_.size() == 0) + return dummy; + + size_t ix = 0; + for (ix; ix<cvs1_.size() && cvs1_[ix]->endparam() <= par; ++ix); + if (ix == cvs1_.size()) + --ix; + + return cvs1_[ix]->ParamCurve::point(par); +} + +//=========================================================================== +bool RevEngEdge::append(RevEngEdge* other, double tol) +//=========================================================================== +{ + double tpar1, tpar2; + bool adjacent = isAdjacent(other, tol, tpar1, tpar2); + if (!adjacent) + return false; // Cannot append + + RevEngRegion *adj3, *adj4; + other->getAdjacent(adj3, adj4); + bool first; + if (adjacent1_ == adj3 && adjacent2_ == adj4) + first = true; + else if (adjacent1_ == adj4 && adjacent2_ == adj3) + first = false; + else + return false; // Not an appendable configuration + + size_t ncv1 = cvs1_.size(); + if (ncv1 == 0) + return false; + + size_t ix1 = 0; + for (; ix1<ncv1 && cvs1_[ix1]->endparam() <= tpar1; ++ix1); + if (ix1 == ncv1) + --ix1; + Point ppos1 = cvs1_[ix1]->faceParameter(tpar1); + Point ppos2 = cvs2_[ix1]->faceParameter(tpar1); + + vector<shared_ptr<CurveOnSurface> > cvs3, cvs4; + other->getCurve(cvs3, true); + other->getCurve(cvs4, false); + size_t ncv3 = cvs3.size(); + size_t ix2 = 0; + for (; ix2<ncv3 && cvs3[ix2]->endparam() <= tpar2; ++ix2); + if (ix2 == ncv3) + --ix2; + Point ppos3 = cvs3[ix2]->faceParameter(tpar2); + Point ppos4 = cvs4[ix2]->faceParameter(tpar2); + + if ((!adjacent1_->hasSurface()) || (!adjacent2_->hasSurface())) + return false; // Unexpected + + shared_ptr<ParamSurface> surf1 = adjacent1_->getSurface(0)->surface(); + shared_ptr<ParamSurface> surf2 = adjacent2_->getSurface(0)->surface(); + Point par_eps1 = SurfaceTools::getParEpsilon(*surf1, tol); + Point par_eps2 = SurfaceTools::getParEpsilon(*surf2, tol); + double epspar1 = 0.5*(par_eps1[0], par_eps1[1]); + double epspar2 = 0.5*(par_eps2[0], par_eps2[1]); + double dd1 = ppos1.dist(first ? ppos3 : ppos4); + double dd2 = ppos2.dist(first ? ppos4 : ppos3); + + if (dd1 > epspar1 || dd2 > epspar2) + return false; + + // Try to append + // Copy curves to keep originals in case of failure + vector<shared_ptr<CurveOnSurface> > cvs1_2(ncv1); + for (size_t ki=0; ki<ncv1; ++ki) + cvs1_2[ki] = shared_ptr<CurveOnSurface>(cvs1_[ki]->clone()); + vector<shared_ptr<CurveOnSurface> > cvs2_2(ncv1); + for (size_t ki=0; ki<ncv1; ++ki) + cvs2_2[ki] = shared_ptr<CurveOnSurface>(cvs2_[ki]->clone()); + vector<shared_ptr<CurveOnSurface> > cvs3_2(ncv3); + for (size_t ki=0; ki<ncv3; ++ki) + cvs3_2[ki] = shared_ptr<CurveOnSurface>(cvs3[ki]->clone()); + vector<shared_ptr<CurveOnSurface> > cvs4_2(ncv3); + for (size_t ki=0; ki<ncv3; ++ki) + cvs4_2[ki] = shared_ptr<CurveOnSurface>(cvs4[ki]->clone()); + + if (fabs(tpar1-cvs1_2[0]->startparam()) < fabs(cvs1_2[ncv1-1]->endparam()-tpar1)) + { + for (size_t ki=0; ki<ncv1; ++ki) + { + cvs1_2[ki]->reverseParameterDirection(); + cvs2_2[ki]->reverseParameterDirection(); + } + for (size_t ki=0; ki<ncv1/2; ++ki) + { + std::swap(cvs1_2[ki], cvs1_2[ncv1-1-ki]); + std::swap(cvs2_2[ki], cvs2_2[ncv1-1-ki]); + } + } + + if (fabs(tpar2-cvs3_2[0]->startparam()) > fabs(cvs3_2[ncv3-1]->endparam()-tpar2)) + { + for (size_t ki=0; ki<ncv3; ++ki) + { + cvs3_2[ki]->reverseParameterDirection(); + cvs4_2[ki]->reverseParameterDirection(); + } + for (size_t ki=0; ki<ncv3/2; ++ki) + { + std::swap(cvs3_2[ki], cvs3_2[ncv3-1-ki]); + std::swap(cvs4_2[ki], cvs4_2[ncv3-1-ki]); + } + } + + // Do append + double dist1, dist2; + if (first) + { + cvs1_2[ncv1-1]->appendCurve(cvs3_2[0].get(), 1, dist1, false, epspar1); + cvs2_2[ncv1-1]->appendCurve(cvs4_2[0].get(), 1, dist2, false, epspar2); + } + else + { + cvs1_2[ncv1-1]->appendCurve(cvs4_2[0].get(), 1, dist1, false, epspar1); + cvs2_2[ncv1-1]->appendCurve(cvs2_2[0].get(), 1, dist2, false, epspar2); + } + + if (dist1 > tol || dist2 > tol) + return false; + + // Check that the parameter curves of the joined curves exists + if ((!cvs1_2[ncv1-1]->hasParameterCurve()) || + (!cvs2_2[ncv1-1]->hasParameterCurve())) + return false; + + // Replace curves + cvs1_.clear(); + cvs1_.insert(cvs1_.end(), cvs1_2.begin(), cvs1_2.end()); + if (first && cvs3_2.size() > 1) + cvs1_.insert(cvs1_.end(), cvs3_2.begin()+1, cvs3_2.end()); + else if ((!first) && cvs4_2.size() > 1) + cvs1_.insert(cvs1_.end(), cvs4_2.begin()+1, cvs4_2.end()); + + cvs2_.clear(); + cvs2_.insert(cvs2_.end(), cvs2_2.begin(), cvs2_2.end()); + if (first && cvs4_2.size() > 1) + cvs2_.insert(cvs2_.end(), cvs4_2.begin()+1, cvs4_2.end()); + else if ((!first) && cvs4_2.size() > 1) + cvs2_.insert(cvs2_.end(), cvs3_2.begin()+1, cvs3_2.end()); + + for (size_t kj=0; kj<other->blend_regs_.size(); ++kj) + other->blend_regs_[kj]->setAssociatedBlend(this); + blend_regs_.insert(blend_regs_.end(), other->blend_regs_.begin(), + other->blend_regs_.end()); + other->clearBlendRegions(); + + distance_ = 0.5*(distance_ + other->distance_); + radius_ = 0.5*(radius_ + other->radius_); + + return true; +} + +//=========================================================================== +int RevEngEdge::missingParCrv() +//=========================================================================== +{ + int missing = 0; + for (size_t ki=0; ki<cvs1_.size(); ++ki) + if (!cvs1_[ki]->hasParameterCurve()) + { + missing += 1; + break; + } + + for (size_t ki=0; ki<cvs2_.size(); ++ki) + if (!cvs2_[ki]->hasParameterCurve()) + { + missing += 2; + break; + } + return missing; +} + +//=========================================================================== +void RevEngEdge::splitAtSeam(double tol, + vector<shared_ptr<RevEngEdge> >& added_edgs, + vector<shared_ptr<RevEngRegion> >& added_regs, + vector<shared_ptr<HedgeSurface> >& added_sfs) +//=========================================================================== +{ + if ((!adjacent1_->hasSurface()) || (!adjacent2_->hasSurface())) + return; // Something is wrong +#ifdef DEBUG + std::ofstream of("edge_split.g2"); + adjacent1_->writeRegionPoints(of); + adjacent2_->writeRegionPoints(of); + for (size_t ki=0; ki<cvs1_.size(); ++ki) + { + shared_ptr<ParamCurve> tmp = cvs1_[ki]->spaceCurve(); + tmp->writeStandardHeader(of); + tmp->write(of); + } +#endif + shared_ptr<ParamSurface> surf1 = adjacent1_->getSurface(0)->surface(); + shared_ptr<ParamSurface> surf2 = adjacent2_->getSurface(0)->surface(); + shared_ptr<ElementarySurface> elem1 = + dynamic_pointer_cast<ElementarySurface,ParamSurface>(surf1); + shared_ptr<ElementarySurface> elem2 = + dynamic_pointer_cast<ElementarySurface,ParamSurface>(surf2); + + bool close_u1=false, close_u2=false, close_v1=false, close_v2=false; + if (elem1.get()) + elem1->isClosed(close_u1, close_v1); + if (elem2.get()) + elem2->isClosed(close_u2, close_v2); + + RectDomain dom1 = surf1->containingDomain(); + RectDomain dom2 = surf2->containingDomain(); + for (size_t ki=0; ki<cvs1_.size(); ++ki) + { + if (!cvs1_[ki]->hasParameterCurve()) + { + // Try to split curve + if (close_u1) + { + vector<shared_ptr<ParamCurve> > seam = + surf1->constParamCurves(dom1.umin(), false); + + shared_ptr<ParamCurve> space = cvs1_[ki]->spaceCurve(); + double par1, par2, dist; + Point ptc1, ptc2; + ClosestPoint::closestPtCurves(space.get(), seam[0].get(), + par1, par2, dist, ptc1, ptc2); + if (dist < tol) + { +#ifdef DEBUG + std::ofstream of2("int_with_seam.g2"); + space->writeStandardHeader(of2); + space->write(of2); + seam[0]->writeStandardHeader(of2); + seam[0]->write(of2); + of2 << "400 1 0 4 255 0 0 255" << std::endl; + of2 << "1" << std::endl; + of2 << ptc1 << std::endl; + of2 << "400 1 0 4 0 255 0 255" << std::endl; + of2 << "1" << std::endl; + of2 << ptc2 << std::endl; +#endif + int nr = 1; + shared_ptr<RevEngEdge> new_edge = + doSplit(ki, nr, par1, tol, added_regs, added_sfs); + if (new_edge.get()) + { + added_edgs.push_back(new_edge); + new_edge->splitAtSeam(tol, added_edgs, added_regs, added_sfs); + } + } + } + + if (close_v1) + { + vector<shared_ptr<ParamCurve> > seam = + surf1->constParamCurves(dom1.vmin(), true); + + shared_ptr<ParamCurve> space = cvs1_[ki]->spaceCurve(); + double par1, par2, dist; + Point ptc1, ptc2; + ClosestPoint::closestPtCurves(space.get(), seam[0].get(), + par1, par2, dist, ptc1, ptc2); + if (dist < tol) + { +#ifdef DEBUG + std::ofstream of2("int_with_seam.g2"); + space->writeStandardHeader(of2); + space->write(of2); + seam[0]->writeStandardHeader(of2); + seam[0]->write(of2); + of2 << "400 1 0 4 255 0 0 255" << std::endl; + of2 << "1" << std::endl; + of2 << ptc1 << std::endl; + of2 << "400 1 0 4 0 255 0 255" << std::endl; + of2 << "1" << std::endl; + of2 << ptc2 << std::endl; +#endif + int nr = 1; + shared_ptr<RevEngEdge> new_edge = + doSplit(ki, nr, par1, tol, added_regs, added_sfs); + if (new_edge.get()) + { + added_edgs.push_back(new_edge); + new_edge->splitAtSeam(tol, added_edgs, added_regs, added_sfs); + } + } + } + } + } + + for (size_t ki=0; ki<cvs2_.size(); ++ki) + { + if (!cvs2_[ki]->hasParameterCurve()) + { + // Try to split curve + if (close_u2) + { + vector<shared_ptr<ParamCurve> > seam = + surf2->constParamCurves(dom2.umin(), false); + + shared_ptr<ParamCurve> space = cvs2_[ki]->spaceCurve(); + double par1, par2, dist; + Point ptc1, ptc2; + ClosestPoint::closestPtCurves(space.get(), seam[0].get(), + par1, par2, dist, ptc1, ptc2); + if (dist < tol) + { +#ifdef DEBUG + std::ofstream of2("int_with_seam.g2"); + space->writeStandardHeader(of2); + space->write(of2); + seam[0]->writeStandardHeader(of2); + seam[0]->write(of2); + of2 << "400 1 0 4 255 0 0 255" << std::endl; + of2 << "1" << std::endl; + of2 << ptc1 << std::endl; + of2 << "400 1 0 4 0 255 0 255" << std::endl; + of2 << "1" << std::endl; + of2 << ptc2 << std::endl; +#endif + int nr = 2; + shared_ptr<RevEngEdge> new_edge = + doSplit(ki, nr, par1, tol, added_regs, added_sfs); + if (new_edge.get()) + { + added_edgs.push_back(new_edge); + new_edge->splitAtSeam(tol, added_edgs, added_regs, added_sfs); + } + } + } + + if (close_v1) + { + vector<shared_ptr<ParamCurve> > seam = + surf1->constParamCurves(dom1.vmin(), true); + + shared_ptr<ParamCurve> space = cvs1_[ki]->spaceCurve(); + double par1, par2, dist; + Point ptc1, ptc2; + ClosestPoint::closestPtCurves(space.get(), seam[0].get(), + par1, par2, dist, ptc1, ptc2); + if (dist < tol) + { +#ifdef DEBUG + std::ofstream of2("int_with_seam.g2"); + space->writeStandardHeader(of2); + space->write(of2); + seam[0]->writeStandardHeader(of2); + seam[0]->write(of2); + of2 << "400 1 0 4 255 0 0 255" << std::endl; + of2 << "1" << std::endl; + of2 << ptc1 << std::endl; + of2 << "400 1 0 4 0 255 0 255" << std::endl; + of2 << "1" << std::endl; + of2 << ptc2 << std::endl; +#endif + int nr = 2; + shared_ptr<RevEngEdge> new_edge = + doSplit(ki, nr, par1, tol, added_regs, added_sfs); + if (new_edge.get()) + { + added_edgs.push_back(new_edge); + new_edge->splitAtSeam(tol, added_edgs, added_regs, added_sfs); + } + } + } + } + } + + +} + + +//=========================================================================== +shared_ptr<RevEngEdge> +RevEngEdge::doSplit(size_t ix, int side, double par, double tol, + vector<shared_ptr<RevEngRegion> >& added_regs, + vector<shared_ptr<HedgeSurface> >& added_sfs) +//=========================================================================== +{ + double eps = 1.0e-9; + shared_ptr<RevEngEdge> new_edg; + if (ix >= cvs1_.size() || cvs1_.size() == 0) + return new_edg; + + if (par <= cvs1_[ix]->startparam()+eps || par >= cvs1_[ix]->endparam()-eps) + return new_edg; + + // Split curves + vector<shared_ptr<ParamCurve> > sub1 = cvs1_[ix]->split(par); + vector<shared_ptr<ParamCurve> > sub2 = cvs2_[ix]->split(par); + if (sub1.size() != 2 || sub2.size() != 2) + return new_edg; + + // Split blend regions + vector<RevEngRegion*> move_reg; + for (size_t ki=0; ki<blend_regs_.size(); ) + { + vector<RevEngPoint*> points = blend_regs_[ki]->getPoints(); + vector<RevEngPoint*> keep, move; + + for (size_t kj=0; kj<points.size(); ++kj) + { + Vector3D xyz = points[kj]->getPoint(); + Point pnt(xyz[0], xyz[1], xyz[2]); + double par2, dist; + Point close; + int ix2; + closestPoint(pnt, par2, close, dist, ix2); + if (ix2 < ix || par2 <= par) + keep.push_back(points[kj]); + else + move.push_back(points[kj]); + } + + if (move.size() == 0) + ++ki; // Do nothing + else if (keep.size() == 0) + { + // Move regions to new edge + move_reg.push_back(blend_regs_[ki]); + blend_regs_.erase(blend_regs_.begin()+ki); + } + else + { + // Split region + blend_regs_[ki]->removePoints(move); // This is not the most effective + // method, but the simplest to implement + blend_regs_[ki]->updateInfo(); + + shared_ptr<RevEngRegion> new_reg(new RevEngRegion(blend_regs_[ki]->getClassificationType(), + blend_regs_[ki]->getEdgeClassificationType(), + move)); + added_regs.push_back(new_reg); + move_reg.push_back(new_reg.get()); + ++ki; + } + } + + // Distribute curves + vector<shared_ptr<CurveOnSurface> > cvs1_2, cvs2_2; + cvs1_2.push_back(dynamic_pointer_cast<CurveOnSurface,ParamCurve>(sub1[1])); + cvs1_2[0]->ensureParCrvExistence(tol); + for (size_t ki=ix+1; ki<cvs1_.size(); ++ki) + cvs1_2.push_back(cvs1_[ki]); + cvs2_2.push_back(dynamic_pointer_cast<CurveOnSurface,ParamCurve>(sub2[1])); + cvs2_2[0]->ensureParCrvExistence(tol); + for (size_t ki=ix+1; ki<cvs2_.size(); ++ki) + cvs2_2.push_back(cvs2_[ki]); + + cvs1_[ix] = dynamic_pointer_cast<CurveOnSurface,ParamCurve>(sub1[0]); + cvs1_[ix]->ensureParCrvExistence(tol); + cvs2_[ix] = dynamic_pointer_cast<CurveOnSurface,ParamCurve>(sub2[0]); + cvs2_[ix]->ensureParCrvExistence(tol); + if (ix < cvs1_.size()-1) + { + cvs1_.erase(cvs1_.begin()+ix+1, cvs1_.end()); + cvs2_.erase(cvs1_.begin()+ix+1, cvs1_.end()); + } + + if (defined_blend_) + { + // Split associated surface + int stop_blend = 1; + } + + new_edg = shared_ptr<RevEngEdge>(new RevEngEdge(blend_type_, adjacent1_, + cvs1_2, outer1_, adjacent2_, + cvs2_2, outer2_, radius_, + distance_)); + adjacent1_->addRevEdge(new_edg.get()); + adjacent2_->addRevEdge(new_edg.get()); + if (move_reg.size() > 0) + { + for (size_t kr=0; kr<move_reg.size(); ++kr) + move_reg[kr]->setAssociatedBlend(new_edg.get()); + new_edg->addBlendRegions(move_reg); + } + + return new_edg; +} + +//=========================================================================== +bool +RevEngEdge::updateCurve(double int_tol, double tol, double len) +//=========================================================================== +{ + double eps = 1.0e-6; + if (surfchangecount_ == 0) + return false; + + if (cvs1_.size() == 0) + return false; + + shared_ptr<ParamSurface> surf1 = adjacent1_->getSurface(0)->surface(); + if (!surf1->isBounded()) + adjacent1_->getSurface(0)->limitSurf(len); + shared_ptr<ParamSurface> surf2 = adjacent2_->getSurface(0)->surface(); + if (!surf2->isBounded()) + adjacent2_->getSurface(0)->limitSurf(len); + shared_ptr<BoundedSurface> bd1, bd2; + vector<shared_ptr<CurveOnSurface> > int_cvs1, int_cvs2; + BoundedUtils::getSurfaceIntersections(surf1, surf2, int_tol, + int_cvs1, bd1, + int_cvs2, bd2); +#ifdef DEBUG_BLEND + std::ofstream of_int("intcurves_edge.g2"); + for (size_t ki=0; ki<cvs1_.size(); ++ki) + { + shared_ptr<ParamCurve> tmp_cv = cvs1_[ki]->spaceCurve(); + tmp_cv->writeStandardHeader(of_int); + tmp_cv->write(of_int); + } + for (size_t ki=0; ki<int_cvs1.size(); ++ki) + { + shared_ptr<ParamCurve> tmp_cv = int_cvs1[ki]->spaceCurve(); + tmp_cv->writeStandardHeader(of_int); + tmp_cv->write(of_int); + } +#endif + // #if 0 + if (isClosed(tol)) + replaceCurves(int_cvs1, int_cvs2); // The seam might have moved + + else + { + if (cvs1_[0]->isClosed()) + { + cvs1_[0] = int_cvs1[0]; + cvs2_[0] = int_cvs2[0]; + } + else + { + size_t st = cvs1_.size() - 1; + Point pos1, pos2, pos3, pos4; + double tdel1 = cvs1_[0]->endparam() - cvs1_[0]->startparam(); + double tdel2 = cvs1_[st]->endparam() - cvs1_[st]->startparam(); + cvs1_[0]->point(pos1, cvs1_[0]->startparam()); + cvs1_[0]->point(pos3, cvs1_[0]->startparam() + 0.1*tdel1); + cvs1_[st]->point(pos2, cvs1_[st]->endparam()); + cvs1_[st]->point(pos4, cvs1_[st]->endparam() - 0.1*tdel2); + double tp1, tp2; + double td1 = std::numeric_limits<double>::max(); + double td2 = std::numeric_limits<double>::max(); + double td3 = std::numeric_limits<double>::max(); + double td4 = std::numeric_limits<double>::max(); + int ix1 = -1, ix2 = -1; + for (size_t kr=0; kr<int_cvs1.size(); ++kr) + { + double tp1_2, tp2_2, tp1_3, tp2_3, td1_2, td2_2, td1_3, td2_3; + Point cl1_2, cl2_2; + double tmin = int_cvs1[kr]->startparam(); + double tmax = int_cvs1[kr]->endparam(); + int_cvs1[kr]->closestPoint(pos1, tmin, tmax, tp1_2, cl1_2, td1_2); + int_cvs1[kr]->closestPoint(pos2, tmin, tmax, tp2_2, cl2_2, td2_2); + int_cvs1[kr]->closestPoint(pos3, tmin, tmax, tp1_3, cl1_2, td1_3); + int_cvs1[kr]->closestPoint(pos4, tmin, tmax, tp2_3, cl2_2, td2_3); + if (td1_2 < td1-eps || (td1_2 <= td1+eps && td1_3 < td3)) + { + ix1 = (int)kr; + tp1 = tp1_2; + td1 = td1_2; + td3 = td1_3; + } + if (td2_2 < td2-eps || (td2_2 <= td2+eps && td2_3 < td4)) + { + ix2 = (int)kr; + tp2 = tp2_2; + td2 = td2_2; + td4 = td2_3; + } + } + + if (ix2 - ix1 + 1 == (int)cvs1_.size() && tp1 < tp2) + { + for (size_t kr=0; kr<int_cvs1.size(); ) + { + double tp3 = std::max(tp1, int_cvs1[kr]->startparam()); + double tp4 = std::min(tp2, int_cvs1[kr]->endparam()); + if (ix1 <= ix2 && ((int)kr < ix1 || (int)kr > ix2)) + { + int_cvs1.erase(int_cvs1.begin()+kr); + int_cvs2.erase(int_cvs2.begin()+kr); + if ((int)kr < ix1) + ix1--; + if ((int)kr < ix2) + ix2--; + } + else if (tp4 > tp3 && tp3 < int_cvs1[kr]->endparam() && + tp4 > int_cvs1[kr]->startparam() && + (tp3 > int_cvs1[kr]->startparam() || tp4 < int_cvs1[kr]->endparam())) + { + shared_ptr<CurveOnSurface> sub1(int_cvs1[kr]->subCurve(tp3, tp4)); + cvs1_[kr] = sub1; + shared_ptr<CurveOnSurface> sub2(int_cvs2[kr]->subCurve(tp3, tp4)); + cvs2_[kr] = sub2; +#ifdef DEBUG_BLEND + shared_ptr<ParamCurve> tmp_cv = sub1->spaceCurve(); + tmp_cv->writeStandardHeader(of_int); + tmp_cv->write(of_int); +#endif + ++kr; + } + else + { + cvs1_[kr] = int_cvs1[kr]; + cvs2_[kr] = int_cvs2[kr]; + ++kr; + } + } + } + } + } + + resetSurfChangeCount(); + return true; + +} + +//=========================================================================== +void +RevEngEdge::updateParCurve(RevEngRegion *adj, double int_tol) +//=========================================================================== +{ + if (adj == adjacent1_) + { + for (size_t ki=0; ki<cvs1_.size(); ++ki) + cvs1_[ki]->ensureParCrvExistence(int_tol); + } + else if (adj == adjacent2_) + { + for (size_t ki=0; ki<cvs2_.size(); ++ki) + cvs2_[ki]->ensureParCrvExistence(int_tol); + } +} + +//=========================================================================== +bool +RevEngEdge::extendCurve(double int_tol, double tol, double anglim, + double len, double lenlim, double blendlim, + vector<shared_ptr<RevEngRegion> >& added_regions, + vector<vector<RevEngPoint*> >& extract_groups, + vector<HedgeSurface*>& out_sfs) +//=========================================================================== +{ + double eps = 1.0e-6; + if (extendcount_ == 0) + return false; + + if (cvs1_.size() == 0) + return false; + + if (isClosed(tol)) + { + extendcount_ = 0; + return false; // Nothing to do here + } + + shared_ptr<ParamSurface> surf1 = adjacent1_->getSurface(0)->surface(); + if (!surf1->isBounded()) + adjacent1_->getSurface(0)->limitSurf(len); + shared_ptr<ParamSurface> surf2 = adjacent2_->getSurface(0)->surface(); + if (!surf2->isBounded()) + adjacent2_->getSurface(0)->limitSurf(len); + shared_ptr<BoundedSurface> bd1, bd2; + vector<shared_ptr<CurveOnSurface> > int_cvs1, int_cvs2; + BoundedUtils::getSurfaceIntersections(surf1, surf2, int_tol, + int_cvs1, bd1, + int_cvs2, bd2); +#ifdef DEBUG_BLEND + std::ofstream of_int("intcurves_edge.g2"); + for (size_t ki=0; ki<cvs1_.size(); ++ki) + { + shared_ptr<ParamCurve> tmp_cv = cvs1_[ki]->spaceCurve(); + tmp_cv->writeStandardHeader(of_int); + tmp_cv->write(of_int); + } + for (size_t ki=0; ki<int_cvs1.size(); ++ki) + { + shared_ptr<ParamCurve> tmp_cv = int_cvs1[ki]->spaceCurve(); + tmp_cv->writeStandardHeader(of_int); + tmp_cv->write(of_int); + } +#endif + + if (int_cvs1.size() == 0) + return false; + + if (int_cvs1.size() > cvs1_.size()) + { + // Remove possible extra curves + vector<Point> mid(cvs1_.size()); + for (size_t ki=0; ki<cvs1_.size(); ++ki) + cvs1_[ki]->point(mid[ki], 0.5*(cvs1_[ki]->startparam()+cvs1_[ki]->endparam())); + size_t kr, kh; + for (kr=0; kr<int_cvs1.size(); ) + { + for (kh=0; kh<mid.size(); ++kh) + { + double tpar, dist; + Point close; + int_cvs1[kr]->closestPoint(mid[kh], int_cvs1[kr]->startparam(), + int_cvs1[kr]->endparam(), tpar, close, dist); + if (dist <= tol) + break; + } + if (kh == mid.size()) + { + int_cvs1.erase(int_cvs1.begin()+kr); + int_cvs2.erase(int_cvs2.begin()+kr); + } + else + ++kr; + } + } + + // Limit intersection curves to relevant intervals + vector<pair<double,double> > t1_t2, t3_t4; + bool OK1 = + adjacent1_->getCurveRestriction(int_cvs1, tol, anglim, t1_t2); + bool OK2 = + adjacent2_->getCurveRestriction(int_cvs2, tol, anglim, t3_t4); + + for (int ka=(int)int_cvs1.size()-1; ka>=0; --ka) + { + double t1 = std::max(t1_t2[ka].first, t3_t4[ka].first); + double t2 = std::min(t1_t2[ka].second, t3_t4[ka].second); + if (t2 > t1 && (t1 > int_cvs1[ka]->startparam() || + t2 < int_cvs1[ka]->endparam())) + { + double pmin = std::max(t1, int_cvs1[ka]->startparam()); + double pmax = std::min(t2, int_cvs1[ka]->endparam()); + shared_ptr<CurveOnSurface> sub1(int_cvs1[ka]->subCurve(pmin,pmax)); + int_cvs1[ka] = sub1; + shared_ptr<CurveOnSurface> sub2(int_cvs2[ka]->subCurve(pmin,pmax)); + int_cvs2[ka] = sub2; + } + + if (t2 <= t1 || int_cvs1[ka]->estimatedCurveLength() < lenlim) + { + int_cvs1.erase(int_cvs1.begin()+ka); + int_cvs2.erase(int_cvs2.begin()+ka); + } + } + if (int_cvs1.size() == 0) + return false; + + vector<RevEngRegion*> common_reg2 = + adjacent1_->commonAdjacent(adjacent2_); + for (size_t kj=0; kj<common_reg2.size(); ) + { + // Check if the common region is registered already or is unfeasable for a blend + size_t kr=0; + for (kr=0; kr<blend_regs_.size(); ++kr) + if (common_reg2[kj] == blend_regs_[kr]) + break; + + if (kr < blend_regs_.size() || common_reg2[kj]->hasAssociatedBlend() || + common_reg2[kj]->hasBlendEdge()) + common_reg2.erase(common_reg2.begin()+kj); + else + ++kj; + } + + // Check extension + vector<RevEngPoint*> bd_pts1 = adjacent1_->extractBdPoints(); + vector<RevEngPoint*> bd_pts2 = adjacent2_->extractBdPoints(); + if (bd_pts1.size() == 0 || bd_pts2.size() == 0) + return false; + + int num_in_lim1=0, num_in_lim2=0; + vector<pair<double, double> > t5_t6, t7_t8; + vector<double> wwd1, wwd2; + adjacent1_->estimateBlendDimensions(int_cvs1, bd_pts1, tol, blendlim, + t5_t6, wwd1, num_in_lim1); + + adjacent2_->estimateBlendDimensions(int_cvs2, bd_pts2, tol, blendlim, + t7_t8, wwd2, num_in_lim2); + if (num_in_lim1 == 0 || num_in_lim2 == 0) + return false; + if (t5_t6.size() == 0 || t7_t8.size() == 0) + return false; + + Point midp = point(0.5*(startparam() + endparam())); + + int ix1 = -1, ix2 = -1; + double td1 = std::numeric_limits<double>::max(); + double td2 = std::numeric_limits<double>::max(); + for (size_t kj=0; kj<t5_t6.size(); ++kj) + { + double tmid = 0.5*(t5_t6[kj].first + t5_t6[kj].second); + size_t kr; + for (kr=0; kr<int_cvs1.size(); ++kr) + if (int_cvs1[kr]->startparam()-eps <= tmid && int_cvs1[kr]->endparam()+eps >= tmid) + break; + if (kr == int_cvs1.size()) + return false; // Should not happen + + double tpar, tdist; + Point close; + int_cvs1[kr]->closestPoint(midp, t5_t6[kj].first, t5_t6[kj].second, + tpar, close, tdist); + if (tdist < td1) + { + ix1 = (int)kj; + td1 = tdist; + } + } + + for (size_t kj=0; kj<t7_t8.size(); ++kj) + { + double tmid = 0.5*(t7_t8[kj].first + t7_t8[kj].second); + size_t kr; + for (kr=0; kr<int_cvs2.size(); ++kr) + if (int_cvs2[kr]->startparam()-eps <= tmid && int_cvs2[kr]->endparam()+eps >= tmid) + break; + if (kr == int_cvs1.size()) + return false; // Should not happen + + double tpar, tdist; + Point close; + int_cvs2[kr]->closestPoint(midp, t7_t8[kj].first, t7_t8[kj].second, + tpar, close, tdist); + if (tdist < td2) + { + ix2 = (int)kj; + td2 = tdist; + } + } + + double t1 = std::max(t5_t6[ix1].first, t7_t8[ix2].first); + double t2 = std::min(t5_t6[ix1].second, t7_t8[ix2].second); + if (t2 <= t1+eps) + return false; // Nothing left + + for (int ka=(int)int_cvs1.size()-1; ka>=0; --ka) + { + if (t2 > t1 && (t1 > int_cvs1[ka]->startparam() || + t2 < int_cvs1[ka]->endparam())) + { + double pmin = std::max(t1, int_cvs1[ka]->startparam()); + double pmax = std::min(t2, int_cvs1[ka]->endparam()); + shared_ptr<CurveOnSurface> sub1(int_cvs1[ka]->subCurve(pmin,pmax)); + int_cvs1[ka] = sub1; + shared_ptr<CurveOnSurface> sub2(int_cvs2[ka]->subCurve(pmin,pmax)); + int_cvs2[ka] = sub2; + } + + if (t2 <= t1 || int_cvs1[ka]->estimatedCurveLength() < lenlim) + { + int_cvs1.erase(int_cvs1.begin()+ka); + int_cvs2.erase(int_cvs2.begin()+ka); + } + } + if (int_cvs1.size() == 0) + return false; + + // Adjust added common regions + vector<RevEngRegion*> adj_regs; + if (common_reg2.size() > 0) + { + int state = (surf1->instanceType() == Class_Plane || + surf2->instanceType() == Class_Plane) ? 1 : 2; + double angtol = 5.0*anglim; + double tol10 = 10.0*tol; + vector<RevEngPoint*> near_pts; + for (size_t kr=0; kr<common_reg2.size(); ++kr) + { + vector<RevEngPoint*> adj_near1, adj_near2; + double dummy_min = 0.0; + for (size_t kh=0; kh<int_cvs1.size(); ++kh) + { + double tmin3 = int_cvs1[kh]->startparam(); + double tmax3 = int_cvs1[kh]->endparam(); + common_reg2[kr]->getNearPoints(int_cvs1[kh], tmin3, tmax3, distance_, + angtol, adj_near1); + if (state == 1) + { + adj_near2 = + adjacent1_->removeOutOfSurf(adj_near1, tol10, + angtol, outer1_, dummy_min); + near_pts = + adjacent2_->removeOutOfSurf(adj_near2, tol10, + angtol, outer2_, dummy_min); + } + else + near_pts = adj_near1; + } + + if ((int)near_pts.size() == common_reg2[kr]->numPoints()) + adj_regs.push_back(common_reg2[kr]); + else if ((int)near_pts.size() < common_reg2[kr]->numPoints()) + { + int num_init = common_reg2[kr]->numPoints(); + vector<vector<RevEngPoint*> > out_groups; + vector<HedgeSurface*> out_sfs; + vector<vector<RevEngPoint*> > near_groups; + common_reg2[kr]->extractSpesPoints(near_pts, near_groups); + common_reg2[kr]->updateInfo(); + common_reg2[kr]->splitRegion(extract_groups); + if (common_reg2[kr]->hasSurface() && + common_reg2[kr]->numPoints() < num_init/2) + { + int num_sf = common_reg2[kr]->numSurface(); + for (int ka=0; ka<num_sf; ++ka) + out_sfs.push_back(common_reg2[kr]->getSurface(ka)); + common_reg2[kr]->clearSurface(); + } + + // Make new region + shared_ptr<RevEngRegion> curr_adj(new RevEngRegion(common_reg2[kr]->getClassificationType(), + common_reg2[kr]->getEdgeClassificationType(), + near_pts)); + added_regions.push_back(curr_adj); + adj_regs.push_back(curr_adj.get()); + } + + } + } + + // Update current edge + replaceCurves(int_cvs1, int_cvs2); + if (adj_regs.size() > 0) + addBlendRegions(adj_regs); + for (size_t kr=0; kr<adj_regs.size(); ++kr) + adj_regs[kr]->setAssociatedBlend(this); + extendcount_ = 0; + + return true; +} + + +//=========================================================================== +void +RevEngEdge::setTrimCurves(double tol, double angtol, + vector<RevEngRegion*>& out_regs, + vector<HedgeSurface*>& out_sfs) +//=========================================================================== +{ + if (blend_type_ != NOT_BLEND) + return; + + // Ensure parameter curve existence + for (size_t ki=0; ki<cvs1_.size(); ++ki) + if (!cvs1_[ki]->hasParameterCurve()) + cvs1_[ki]->ensureParCrvExistence(tol); + + for (size_t ki=0; ki<cvs2_.size(); ++ki) + if (!cvs2_[ki]->hasParameterCurve()) + cvs2_[ki]->ensureParCrvExistence(tol); + + // Distribute points along the curve as appropriate + // Start with the inbetween points +#ifdef DEBUG_BLEND + std::ofstream of1("init_points.g2"); + adjacent1_->writeRegionPoints(of1); + adjacent2_->writeRegionPoints(of1); + for (size_t kj=0; kj<blend_regs_.size(); ++kj) + blend_regs_[kj]->writeRegionPoints(of1); + for (size_t kj=0; kj<cvs1_.size(); ++kj) + { + cvs1_[kj]->spaceCurve()->writeStandardHeader(of1); + cvs1_[kj]->spaceCurve()->write(of1); + } +#endif + for (int ka=(int)blend_regs_.size()-1; ka>=0; --ka) + { + vector<RevEngPoint*> points = blend_regs_[ka]->getPoints(); + vector<RevEngPoint*> move1, move2; + adjacent1_->sortBlendPoints(points, cvs1_, 0.0, adjacent2_, + move1, move2); + blend_regs_[ka]->removePoints(move1); + adjacent1_->addPointsToGroup(move1, tol, angtol); + adjacent2_->addPointsToGroup(move2, tol, angtol); + blend_regs_[ka]->removePoints(move2); + if (blend_regs_[ka]->hasSurface()) + { + int num_sf = blend_regs_[ka]->numSurface(); + for (int kb=0; kb<num_sf; ++kb) + out_sfs.push_back(blend_regs_[ka]->getSurface(kb)); + blend_regs_[ka]->clearSurface(); + } + + if (blend_regs_[ka]->numPoints() == 0) + { + blend_regs_[ka]->removeFromAdjacent(); + blend_regs_[ka]->clearRegionAdjacency(); + out_regs.push_back(blend_regs_[ka]); + blend_regs_.erase(blend_regs_.begin()+ka); + } + int stop_break0 = 1; + } + + vector<RevEngPoint*> move_adj1, move_adj2; + bool do_move = false; + if (do_move) + { + adjacent1_->extractOutOfEdge2(cvs1_, tol, angtol, move_adj1); + adjacent2_->extractOutOfEdge2(cvs2_, tol, angtol, move_adj2); + } +#ifdef DEBUG_BLEND + std::ofstream of2("move_points.g2"); + adjacent1_->writeRegionPoints(of2); + if (move_adj1.size() > 0) + { + of2 << "400 1 0 4 255 0 0 255" << std::endl; + of2 << move_adj1.size() << std::endl; + for (size_t kj=0; kj<move_adj1.size(); ++kj) + of2 << move_adj1[kj]->getPoint() << std::endl; + } + adjacent2_->writeRegionPoints(of2); + if (move_adj2.size() > 0) + { + of2 << "400 1 0 4 0 255 0 255" << std::endl; + of2 << move_adj2.size() << std::endl; + for (size_t kj=0; kj<move_adj2.size(); ++kj) + of2 << move_adj2[kj]->getPoint() << std::endl; + } + for (size_t kj=0; kj<cvs1_.size(); ++kj) + { + cvs1_[kj]->spaceCurve()->writeStandardHeader(of2); + cvs1_[kj]->spaceCurve()->write(of2); + } +#endif + if (move_adj1.size() > 0) + adjacent2_->addPointsToGroup(move_adj1, tol, angtol); + if (move_adj2.size() > 0) + adjacent1_->addPointsToGroup(move_adj2, tol, angtol); + + // Define trim curves + int stat = 0; + for (size_t ki=0; ki<cvs1_.size(); ++ki) + { + shared_ptr<ftEdge> edg1(new ftEdge(adjacent1_->getSurface(0), + cvs1_[ki], cvs1_[ki]->startparam(), + cvs1_[ki]->endparam())); + shared_ptr<ftEdge> edg2(new ftEdge(adjacent2_->getSurface(0), + cvs2_[ki], cvs2_[ki]->startparam(), + cvs2_[ki]->endparam())); + edg2->setReversed(true); + edg1->connectTwin(edg2.get(), stat); + adjacent1_->addTrimEdge(edg1); + adjacent2_->addTrimEdge(edg2); + } + + int stop_break = 1; +} + + +//=========================================================================== +bool +RevEngEdge::contains(RevEngEdge *other, double tol) +//=========================================================================== +{ + if (!((adjacent1_ == other->adjacent1_ && adjacent2_ == other->adjacent2_) || + (adjacent1_ == other->adjacent2_ && adjacent2_ == other->adjacent1_))) + return false; // Not the same adjacent surfaces (groups) + + // Assumes only one curve associated to the edge + Identity ident; + int stat = ident.identicalCvs(cvs1_[0], other->cvs1_[0], tol); + if (stat == 1 || stat == 3) + return true; + else + return false; +} + +//=========================================================================== +bool +RevEngEdge::integrate(RevEngEdge *other) +//=========================================================================== +{ + if (!((adjacent1_ == other->adjacent1_ && adjacent2_ == other->adjacent2_) || + (adjacent1_ == other->adjacent2_ && adjacent2_ == other->adjacent1_))) + return false; // Not the same adjacent surfaces (groups) + + if (defined_blend_ && defined_blend_ != other->defined_blend_) + return false; + + for (size_t ki=0; ki<other->blend_regs_.size(); ++ki) + other->blend_regs_[ki]->setAssociatedBlend(this); + + other->clearBlendRegions(); + + return true; +} diff --git a/compositemodel/src/RevEngPoint.C b/compositemodel/src/RevEngPoint.C new file mode 100644 index 00000000..9c70961f --- /dev/null +++ b/compositemodel/src/RevEngPoint.C @@ -0,0 +1,788 @@ +/* + * Copyright (C) 1998, 2000-2007, 2010, 2011, 2012, 2013 SINTEF ICT, + * Applied Mathematics, Norway. + * + * Contact information: E-mail: tor.dokken@sintef.no + * SINTEF ICT, Department of Applied Mathematics, + * P.O. Box 124 Blindern, + * 0314 Oslo, Norway. + * + * This file is part of GoTools. + * + * GoTools is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * GoTools 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with GoTools. If not, see + * <http://www.gnu.org/licenses/>. + * + * In accordance with Section 7(b) of the GNU Affero General Public + * License, a covered work must retain the producer line in every data + * file that is created or manipulated using GoTools. + * + * Other Usage + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial activities involving the GoTools library without + * disclosing the source code of your own applications. + * + * This file may be used in accordance with the terms contained in a + * written agreement between you and SINTEF ICT. + */ + +#include "GoTools/compositemodel/RevEngPoint.h" +#include "GoTools/compositemodel/RevEngRegion.h" +#include "GoTools/utils/Array.h" +#include "GoTools/utils/Point.h" +#include <vector> + +using namespace Go; +using std::vector; + +//=========================================================================== +RevEngPoint::RevEngPoint() + : ftSamplePoint() +//=========================================================================== +{ + int dim = 3; + eigen1_ = Point(dim); + eigen2_ = Point(dim); + eigen3_ = Point(dim); + LocFuncnormal_ = Point(dim); + kvecmin_ = Point(dim); + kvecmax_ = Point(dim); + lambda1_ = lambda2_ = lambda3_ = -1.0; + kmin_ = kmax_ = 0.0; + ptdist_ = avdist_ = 0.0; + nmb_eigen_ = nmb_locfunc_ = 0; + Point dummy(0.0, 0.0, 0.0); + // normalcone_.setFromArray(dummy.begin(), dummy.end(), 3); + normalcone_ = DirectionCone(dummy); + avedglen_ = -1.0; + region_ = 0; + visited_ = 0; + moved_ = 0; + outlier_ = false; + mark_ix_ = -1; + sfdist_ = -1.0; + sfang_ = -1.0; + nmb_move_ = 0; + meancurv0_ = meancurv_ = gausscurv0_ = gausscurv_ = 0.0; + curvedness_ = 0.0; + edge_[0] = PCA_EDGE_UNDEF; + edge_[1] = C1_EDGE_UNDEF; + edge_[2] = C2_EDGE_UNDEF; + surf_[0] = PCA_UNDEF; + surf_[1] = C1_UNDEF; +} + +//=========================================================================== +RevEngPoint::RevEngPoint(Vector3D xyz, int bnd) + : ftSamplePoint(xyz, bnd) +//=========================================================================== +{ + int dim = 3; + eigen1_ = Point(dim); + eigen2_ = Point(dim); + eigen3_ = Point(dim); + LocFuncnormal_ = Point(dim); + kvecmin_ = Point(dim); + kvecmax_ = Point(dim); + lambda1_ = lambda2_ = lambda3_ = -1.0; + kmin_ = kmax_ = 0.0; + ptdist_ = avdist_ = 0.0; + nmb_eigen_ = nmb_locfunc_ = 0; + Point dummy(0.0, 0.0, 0.0); + // normalcone_.setFromArray(dummy.begin(), dummy.end(), 3); + normalcone_ = DirectionCone(dummy); + avedglen_ = -1.0; + region_ = 0; + visited_ = 0; + outlier_ = false; + mark_ix_ = -1; + sfdist_ = -1.0; + sfang_ = -1.0; + nmb_move_ = 0; + meancurv0_ = meancurv_ = gausscurv0_ = gausscurv_ = 0.0; + curvedness_ = 0.0; + edge_[0] = PCA_EDGE_UNDEF; + edge_[1] = C1_EDGE_UNDEF; + edge_[2] = C2_EDGE_UNDEF; + surf_[0] = PCA_UNDEF; + surf_[1] = C1_UNDEF; +} + +//=========================================================================== +RevEngPoint::~RevEngPoint() +//=========================================================================== +{ +} + +//=========================================================================== +double RevEngPoint::getMeanEdgLen() +//=========================================================================== +{ + if (avedglen_ < 0.0) + { + double len = 0.0; + for (size_t ki=0; ki<next_.size(); ++ki) + { + double currlen = xyz_.dist(next_[ki]->getPoint()); + len += currlen; + } + if (next_.size() > 0) + len /= (double)next_.size(); + avedglen_ = len; + } + return avedglen_; + +} + +//=========================================================================== +double RevEngPoint::getMeanEdgLen(double maxlen) +//=========================================================================== +{ + int nmb = 0; + double len = 0.0; + for (size_t ki=0; ki<next_.size(); ++ki) + { + double currlen = xyz_.dist(next_[ki]->getPoint()); + if (currlen > maxlen) + continue; + len += currlen; + ++nmb; + } + if (nmb > 0) + len /= (double)nmb; + return len; + +} + +//=========================================================================== +void RevEngPoint::computeTriangNormal(double lim) +//=========================================================================== +{ + if (next_.size() == 0) + return; + double eps = 1.0e-10; + size_t prev = next_.size()-1; + Vector3D vec1 = next_[prev]->getPoint() - xyz_; + + size_t ki, kj; + for (ki=0, kj=0; ki<next_.size(); prev=ki, ++ki) + { + Vector3D vec2 = next_[ki]->getPoint() - xyz_; + Vector3D norm = vec1 % vec2; + bool neighbour = next_[ki]->isNeighbour(next_[prev]); + + if (neighbour && vec1.length() <= lim && vec2.length() <= lim && + norm.length() > eps) + { + if (kj == 0) + normalcone_.setFromArray(norm.begin(), norm.end(), 3); + else + { + Point norm2(norm[0], norm[1], norm[2]); + normalcone_.addUnionWith(norm2); + } + ++kj; + } + else + { + int stop_break = 1; + } + vec1 = vec2; + } + if (kj == 0) + setOutlier(); +} + +//=========================================================================== +int RevEngPoint::surfaceClassification(int classification_type) const +//=========================================================================== +{ + if (classification_type == CLASSIFICATION_CURVATURE) + return surf_[1]; + else if (classification_type == CLASSIFICATION_SHAPEINDEX) + return surf_[2]; + else if (classification_type == CLASSIFICATION_POINTASSOCIATION) + return surf_[3]; + else + return CLASSIFICATION_UNDEF; + } + +//=========================================================================== +Point RevEngPoint::fetchClosePoints(double radius, int min_nmb, int max_nmb, + vector<Point>& nearpts) +//=========================================================================== +{ + int nmb_iter = 0; + int max_iter = 5; + // Debug + DirectionCone pcone = normalcone_; + while ((int)nearpts.size() < min_nmb) + { + setVisited(); + vector<RevEngPoint*> near; + for (size_t ki=0; ki<next_.size(); ++ki) + { + RevEngPoint* curr = dynamic_cast<RevEngPoint*>(next_[ki]); + if (curr->visited()) + continue; + if (xyz_.dist(curr->getPoint()) <= radius) + { + curr->setVisited(); + near.push_back(curr); + pcone.addUnionWith(curr->normalcone_); + curr->getNearby(xyz_, radius, max_nmb, near); + } + } + + unsetVisited(); + for (size_t ki=0; ki<near.size(); ++ki) + { + Vector3D vx = near[ki]->getPoint(); + nearpts.push_back(Point(vx[0], vx[1], vx[2])); + near[ki]->unsetVisited(); + pcone.addUnionWith(near[ki]->normalcone_); + } + + if (nmb_iter > max_iter) + break; + + if (nearpts.size() < min_nmb) + { + radius *= std::max(1.1, (double)min_nmb/(double)nearpts.size()); + nearpts.clear(); + } + ++nmb_iter; + } + + return Point(xyz_[0], xyz_[1], xyz_[2]); +} + +//=========================================================================== +void RevEngPoint::fetchClosePoints2(double radius, int min_nmb, int max_nmb, + vector<RevEngPoint*>& nearpts, + RevEngRegion *region) +//=========================================================================== +{ + int nmb_iter = 0; + int max_iter = 5; + size_t prev_nmb = nearpts.size(); + int nmb_same = 0; + while ((int)nearpts.size() < min_nmb) + { + setVisited(); + vector<RevEngPoint*> near; + for (size_t ki=0; ki<next_.size(); ++ki) + { + RevEngPoint* curr = dynamic_cast<RevEngPoint*>(next_[ki]); + if (curr->visited()) + continue; + if (region && curr->region() != region) + continue; + if (xyz_.dist(curr->getPoint()) <= radius) + { + curr->setVisited(); + near.push_back(curr); + curr->getNearby(xyz_, radius, max_nmb, near, region); + } + } + + unsetVisited(); + for (size_t ki=0; ki<near.size(); ++ki) + { + nearpts.push_back(near[ki]); + near[ki]->unsetVisited(); + } + + if (nmb_iter > max_iter) + break; + + if (nearpts.size() == prev_nmb) + ++nmb_same; + prev_nmb = nearpts.size(); + if (nearpts.size() < min_nmb && nmb_iter < max_iter) + { + radius *= std::max(1.1, (double)min_nmb/(double)nearpts.size()); + nearpts.clear(); + } + ++nmb_iter; + } + // // Debug + // DirectionCone pcone = normalcone_; + // for (size_t ki=0; ki<nearpts.size(); ++ki) + // pcone.addUnionWith(nearpts[ki]->normalcone_); + if (nearpts.size() < min_nmb && nmb_same > 0) + { + for (size_t ki=0; ki<nearpts.size(); ++ki) + nearpts[ki]->setOutlier(); + nearpts.clear(); + } + int stop_break = 1; +} + +//=========================================================================== +void RevEngPoint::fetchConnected(RevEngRegion *region, int max_nmb, + vector<RevEngPoint*>& group) +//=========================================================================== +{ + setVisited(); + group.push_back(this); + for (size_t ki=0; ki<group.size(); ++ki) + { + vector<ftSamplePoint*> next = group[ki]->getNeighbours(); + for (size_t kj=0; kj<next.size(); ++kj) + { + RevEngPoint* curr = dynamic_cast<RevEngPoint*>(next[kj]); + if (curr->visited()) + continue; + if (curr->region() != region) + continue; + curr->setVisited(); + group.push_back(curr); + } + if ((int)group.size() >= max_nmb) + break; + } +// double radius = std::numeric_limits<double>::max(); + +// setVisited(); +// vector<RevEngPoint*> connected; +// for (size_t ki=0; ki<next_.size(); ++ki) +// { +// RevEngPoint* curr = dynamic_cast<RevEngPoint*>(next_[ki]); +// if (curr->visited()) +// continue; +// if (curr->region() != region) +// continue; +// curr->setVisited(); +// connected.push_back(curr); +// curr->getNearby(xyz_, radius, max_nmb, connected, region); +// } +// group.push_back(this); +// group.insert(group.end(), connected.begin(), connected.end()); + int stop_break = 1; +} + +//=========================================================================== +void RevEngPoint::fetchConnectedMarked(int mark, + vector<RevEngPoint*>& group) +//=========================================================================== +{ + setVisited(); + group.push_back(this); + for (size_t ki=0; ki<group.size(); ++ki) + { + vector<ftSamplePoint*> next = group[ki]->getNeighbours(); + for (size_t kj=0; kj<next.size(); ++kj) + { + RevEngPoint* curr = dynamic_cast<RevEngPoint*>(next[kj]); + if (curr->visited()) + continue; + if (curr->getMarkIx() != mark) + continue; + curr->setVisited(); + group.push_back(curr); + } + } +} + +///=========================================================================== +void RevEngPoint::getNearby(Vector3D xyz, double radius, int max_nmb, + vector<RevEngPoint*>& near, RevEngRegion* region) +//=========================================================================== +{ + for (size_t ki=0; ki<next_.size(); ++ki) + { + RevEngPoint* curr = dynamic_cast<RevEngPoint*>(next_[ki]); + if (curr->visited()) + continue; + if (region && curr->region() != region) + continue; + if (xyz.dist(curr->getPoint()) <= radius) + { + curr->setVisited(); + near.push_back(curr); + if (near.size() < max_nmb) + curr->getNearby(xyz, radius, max_nmb, near, region); + } + } +} + +//=========================================================================== +void +RevEngPoint::addCovarianceEigen(Point& eigen1, double lambda1, Point& eigen2, + double lambda2, Point& eigen3, double lambda3) +//=========================================================================== +{ + if (nmb_eigen_ == 0) + { + eigen1_ = eigen1; + eigen2_ = eigen2; + eigen3_ = eigen3; + lambda1_ = lambda1; + lambda2_ = lambda2; + lambda3_ = lambda3; + } + else + { + eigen1_ = nmb_eigen_*eigen1_ + eigen1; + eigen2_ = nmb_eigen_*eigen2_ + eigen2; + eigen3_ = nmb_eigen_*eigen3_ + eigen3; + lambda1_ = nmb_eigen_*lambda1_ + lambda1; + lambda2_ = nmb_eigen_*lambda2_ + lambda2; + lambda3_ = nmb_eigen_*lambda3_ + lambda3; + eigen1_ /= (double)(nmb_eigen_+1); + eigen2_ /= (double)(nmb_eigen_+1); + eigen3_ /= (double)(nmb_eigen_+1); + lambda1_ /= (double)(nmb_eigen_+1); + lambda2_ /= (double)(nmb_eigen_+1); + lambda3_ /= (double)(nmb_eigen_+1); + } + nmb_eigen_++; +} + +//=========================================================================== +void RevEngPoint::addLocFuncInfo(Point& norm, Point& mincvec, double minc, Point& maxcvec, + double maxc, double currdist, double avdist) +//=========================================================================== +{ + if (nmb_locfunc_ == 0) + { + LocFuncnormal_ = norm; + kvecmin_ = mincvec; + kvecmax_ = maxcvec; + kmin_ = minc; + kmax_ = maxc; + ptdist_ = currdist; + avdist_ = avdist; + } + else + { + LocFuncnormal_ = nmb_locfunc_*LocFuncnormal_ + norm; + kvecmin_ = nmb_locfunc_*kvecmin_ + mincvec; + kvecmax_ = nmb_locfunc_*kvecmax_ + maxcvec; + kmin_ = nmb_locfunc_*kmin_ + minc; + kmax_ = nmb_locfunc_*kmax_ + maxc; + ptdist_ = nmb_locfunc_*ptdist_ + currdist; + avdist_ = nmb_locfunc_*avdist_ + avdist; + LocFuncnormal_ /= (double)(nmb_locfunc_+1); + kvecmin_ /= (double)(nmb_locfunc_+1); + kvecmax_ /= (double)(nmb_locfunc_+1); + kmin_ /= (double)(nmb_locfunc_+1); + kmax_ /= (double)(nmb_locfunc_+1); + ptdist_ /= (double)(nmb_locfunc_+1); + avdist_ /= (double)(nmb_locfunc_+1); + } + nmb_locfunc_++; + + meancurv0_ = meancurv_ = 0.5*(kmin_ + kmax_); + gausscurv0_ = gausscurv_ = kmin_*kmax_; + curvedness_ = sqrt(0.5*(kmin_*kmin_ + kmax_*kmax_)); + +} + + +//=========================================================================== +bool RevEngPoint::isolatedEdge(int edge_class_type, int nmb, bool close) +//=========================================================================== +{ + if (notEdge(edge_class_type)) + return false; + + int nn = 0; + for (size_t ki=0; ki<next_.size(); ++ki) + { + RevEngPoint* curr = dynamic_cast<RevEngPoint*>(next_[ki]); + bool found = (close) ? curr->closeEdge(edge_class_type) : + curr->isEdge(edge_class_type); + if (found) + ++nn; + } + return (nn <= nmb); +} + + +//=========================================================================== +void RevEngPoint::adjustWithTriangNorm(double anglim) +//=========================================================================== +{ + double ang = getTriangAngle(); + if (ang < anglim) + { + if (edge_[0] == PCA_EDGE) + edge_[0] = PCA_CLOSE_EDGE; + if (edge_[1] == C1_EDGE) + edge_[1] = C1_CLOSE_EDGE; + if (edge_[2] == C2_EDGE) + edge_[2] = C2_CLOSE_EDGE; + } +} + +//=========================================================================== +void RevEngPoint::adjacentRegions(vector<RevEngRegion*>& adj) const +//=========================================================================== +{ + for (size_t ki=0; ki<next_.size(); ++ki) + { + RevEngPoint *pt = dynamic_cast<RevEngPoint*>(next_[ki]); + if (pt->region_ && pt->region_ != region_) + { + size_t kj; + for (kj=0; kj<adj.size(); ++kj) + if (pt->region_ == adj[kj]) + break; + if (kj == adj.size()) + adj.push_back(pt->region_); + } + } +} + +//=========================================================================== +bool RevEngPoint::nextToRegion(RevEngRegion *reg) +//=========================================================================== +{ + for (size_t ki=0; ki<next_.size(); ++ki) + { + RevEngPoint *pt = dynamic_cast<RevEngPoint*>(next_[ki]); + if (pt->region_ && pt->region_ == reg) + return true; + } + return false; +} + + +//=========================================================================== +int RevEngPoint::nmbSameClassification(int classification_type) const +//=========================================================================== +{ + int same = 0; + int type = surfaceClassification(classification_type); + for (size_t ki=0; ki<next_.size(); ++ki) + { + RevEngPoint *pt = dynamic_cast<RevEngPoint*>(next_[ki]); + if (pt->surfaceClassification(classification_type) == type) + same++; + } + return same; + } + +//=========================================================================== +bool RevEngPoint::isNeighbour(RevEngRegion* reg) const +//=========================================================================== +{ + for (size_t ki=0; ki<next_.size(); ++ki) + { + RevEngPoint *pt = dynamic_cast<RevEngPoint*>(next_[ki]); + if (pt->region() == reg) + return true; + } + return false; +} + +//=========================================================================== +bool RevEngPoint::isNeighbour(RevEngPoint* pt) const +//=========================================================================== +{ + for (size_t ki=0; ki<next_.size(); ++ki) + { + if (pt == next_[ki]) + return true; + } + return false; +} + + + +//=========================================================================== +void RevEngPoint::getAdjInfo(double mean_edge_len, vector<RevEngRegion*>& adj_reg, + vector<RevEngPoint*>& adj_pt) +//=========================================================================== +{ + double fac = 10.0; + for (size_t ki=0; ki<next_.size(); ++ki) + { + if (pntDist(next_[ki]) > fac*mean_edge_len) + continue; + RevEngPoint *pt = dynamic_cast<RevEngPoint*>(next_[ki]); + RevEngRegion *curr = pt->region(); + if (curr) + { + size_t kj; + for (kj=0; kj<adj_reg.size(); ++kj) + { + if (adj_reg[kj] == curr) + { + if (pntDist(pt) < pntDist(adj_pt[kj])) + adj_pt[kj] = pt; + break; + } + } + if (kj == adj_reg.size()) + { + adj_reg.push_back(curr); + adj_pt.push_back(pt); + } + } + } +} + +//=========================================================================== +vector<RevEngRegion*> RevEngPoint::getAdjacentRegions() const +//=========================================================================== +{ + vector<RevEngRegion*> adj_reg; + for (size_t ki=0; ki<next_.size(); ++ki) + { + RevEngPoint *pt = dynamic_cast<RevEngPoint*>(next_[ki]); + RevEngRegion *curr = pt->region(); + size_t kj; + for (kj=0; kj<adj_reg.size(); ++kj) + if (adj_reg[kj] == curr) + break; + if (kj == adj_reg.size()) + adj_reg.push_back(curr); + } + + return adj_reg; +} + +//=========================================================================== +vector<RevEngRegion*> RevEngPoint::adjacentRegsWithSurf() const +//=========================================================================== +{ + vector<RevEngRegion*> adj_reg; + for (size_t ki=0; ki<next_.size(); ++ki) + { + RevEngPoint *pt = dynamic_cast<RevEngPoint*>(next_[ki]); + RevEngRegion *curr = pt->region(); + if (!curr) + continue; + if (!curr->hasSurface()) + continue; + size_t kj; + for (kj=0; kj<adj_reg.size(); ++kj) + if (adj_reg[kj] == curr) + break; + if (kj == adj_reg.size()) + adj_reg.push_back(curr); + } + + return adj_reg; +} + +//=========================================================================== +int RevEngPoint::numAdjacentRegions() const +//=========================================================================== +{ + vector<RevEngRegion*> adj_reg = getAdjacentRegions(); + return (int)adj_reg.size(); +} + +//=========================================================================== +bool RevEngPoint::mergeWithAdjacent(double mean_edge_len) +//=========================================================================== +{ + vector<RevEngRegion*> adj_reg; + vector<RevEngPoint*> adj_pt; + getAdjInfo(mean_edge_len, adj_reg, adj_pt); + + if (adj_reg.size() == 0) + return false; + + double lentol = 2.0*mean_edge_len; + double angtol = 0.1*M_PI; + int minlen = std::numeric_limits<double>::max(); + int minix = -1; + for (size_t ki=0; ki<adj_pt.size(); ++ki) + { + double len = pntDist(adj_pt[ki]); + if (len > lentol) + continue; + Point monge = adj_pt[ki]->getLocFuncNormal(); + if (LocFuncnormal_*monge < 0.0 || LocFuncnormal_.angle(monge) > angtol) + continue; + int ka; + for (ka=1; ka<4; ++ka) + if (surf_[ka] == adj_pt[ki]->surf_[ka]) + break; + if (ka == 4) + continue; + if (len < minlen) + { + minlen = len; + minix = (int)ki; + } + } + + if (minix >= 0) + { + adj_reg[minix]->addPoint(this); + return true; + } + + int stop_break = 1; + return false; +} + +//=========================================================================== +void RevEngPoint::store(std::ostream& os) const +//=========================================================================== +{ + os << index_ << " " << xyz_ << " " << uv_ << std::endl; + os << next_.size(); + for (size_t ki=0; ki<next_.size(); ++ki) + os << " " << next_[ki]->getIndex(); + os << std::endl; + os << avedglen_ << " " << eigen1_ << " " << lambda1_ << " " << eigen2_; + os << " " << lambda2_ << " " << eigen3_ << " " << lambda3_ << std::endl; + os << LocFuncnormal_ << " " << kvecmin_ << " " << kmin_ << " " << kvecmax_; + os << " " << kmax_ << std::endl; + os << ptdist_ << " " << avdist_ << std::endl; + normalcone_.write(os); + for (int ka=0; ka<3; ++ka) + os << " " << edge_[ka]; + for (int ka=0; ka<2; ++ka) + os << " " << surf_[ka]; + os << " " << outlier_ << " " << sfdist_ << " " << sfang_ << std::endl; + os << std::endl; +} + +//=========================================================================== +void RevEngPoint::read(std::istream& is, vector<int>& next_ix) +//=========================================================================== +{ + is >> index_ >> xyz_ >> uv_; + int nmb_next; + is >> nmb_next; + if (nmb_next > 0) + next_ix.resize(nmb_next); + for (int ki=0; ki<nmb_next; ++ki) + is >> next_ix[ki]; + is >> avedglen_ >> eigen1_ >> lambda1_ >> eigen2_ >> lambda2_; + is >> eigen3_ >> lambda3_ >> LocFuncnormal_ >> kvecmin_ >> kmin_; + is >> kvecmax_ >> kmax_ >> ptdist_ >> avdist_; + Point dummy(3); + //normalcone_ = DirectionCone(dummy); + normalcone_.read(is); + meancurv0_ = meancurv_ = 0.5*(kmin_ + kmax_); + gausscurv0_ = gausscurv_ = kmin_*kmax_; + curvedness_ = sqrt(0.5*(kmin_*kmin_ + kmax_*kmax_)); + for (int ka=0; ka<3; ++ka) + is >> edge_[ka]; + for (int ka=0; ka<2; ++ka) + is >> surf_[ka]; + is >> outlier_ >> sfdist_ >> sfang_; + +} + + diff --git a/compositemodel/src/RevEngRegion.C b/compositemodel/src/RevEngRegion.C new file mode 100644 index 00000000..e6e2d533 --- /dev/null +++ b/compositemodel/src/RevEngRegion.C @@ -0,0 +1,18120 @@ +/* + * Copyright (C) 1998, 2000-2007, 2010, 2011, 2012, 2013 SINTEF ICT, + * Applied Mathematics, Norway. + * + * Contact information: E-mail: tor.dokken@sintef.no + * SINTEF ICT, Department of Applied Mathematics, + * P.O. Box 124 Blindern, + * 0314 Oslo, Norway. + * + * This file is part of GoTools. + * + * GoTools is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * GoTools 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with GoTools. If not, see + * <http://www.gnu.org/licenses/>. + * + * In accordance with Section 7(b) of the GNU Affero General Public + * License, a covered work must retain the producer line in every data + * file that is created or manipulated using GoTools. + * + * Other Usage + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial activities involving the GoTools library without + * disclosing the source code of your own applications. + * + * This file may be used in accordance with the terms contained in a + * written agreement between you and SINTEF ICT. + */ + +#include "GoTools/compositemodel/RevEngRegion.h" +#include "GoTools/compositemodel/RevEngPoint.h" +#include "GoTools/compositemodel/RevEngUtils.h" +#include "GoTools/compositemodel/RevEngEdge.h" +#include "GoTools/compositemodel/RevEng.h" +#include "GoTools/compositemodel/HedgeSurface.h" +#include "GoTools/compositemodel/SurfaceModel.h" +#include "GoTools/compositemodel/Loop.h" +#include "GoTools/compositemodel/CompositeModelFactory.h" +#include "GoTools/geometry/Cylinder.h" +#include "GoTools/geometry/Cone.h" +#include "GoTools/geometry/Sphere.h" +#include "GoTools/geometry/Torus.h" +#include "GoTools/geometry/Circle.h" +#include "GoTools/geometry/BoundedSurface.h" +#include "GoTools/geometry/CurveLoop.h" +#include "GoTools/geometry/LoopUtils.h" +#include "GoTools/geometry/PointCloud.h" +//#include "GoTools/utils/Array.h" +//#include "GoTools/utils/Point.h" +#include "GoTools/geometry/SplineCurve.h" +#include "GoTools/geometry/CurveOnSurface.h" +#include "GoTools/geometry/CurveLoop.h" +#include "GoTools/geometry/Curvature.h" +#include "GoTools/geometry/Utils.h" +#include "GoTools/geometry/SweepSurfaceCreator.h" +#include "GoTools/geometry/GoIntersections.h" +#include "GoTools/creators/SmoothCurve.h" +#include "GoTools/creators/ApproxCurve.h" +#include "GoTools/creators/ApproxSurf.h" +#include "GoTools/creators/CurveCreators.h" +// #include "GoTools/creators/SmoothSurf.h" +#include "GoTools/geometry/Factory.h" +#include "GoTools/geometry/GoTools.h" +#include "GoTools/geometry/ObjectHeader.h" +#include "GoTools/geometry/ClosestPoint.h" +#include "GoTools/geometry/GeometryTools.h" +#include "GoTools/geometry/SplineDebugUtils.h" +#include "newmat.h" +#include "newmatap.h" +#include <vector> +#include <fstream> + +//#define DEBUG_JOIN +//#define DEBUG_CHECK +//#define DEBUG_UPDATE +//#define DEBUG_INTEGRATE +//#define DEBUG_TORUSCONTEXT +//#define DEBUG_CYLCONTEXT +//#define DEBUG +//#define DEBUG0 +//#define DEBUG_EXTRACT +//#define DEBUG_CYL +//#define DEBUG_PLANAR +//#define DEBUG_SEGMENT +//#define DEBUG_REPAR +//#define DEBUG_ADJUST +//#define DEBUG_GROW +//#define DEBUG_MERGE +//#define DEBUG_ADJACENT +//#define DEBUG_VALIDATE +//#define DEBUG_COLLECT +//#define DEBUG_AXIS +//#define DEBUG_GROWNEIGHBOUR +//#define DEBUG_TRIM +//#define DEBUG_BLEND + +using namespace Go; +using std::vector; +using std::set; +using std::pair; + +//=========================================================================== +RevEngRegion::RevEngRegion(int edge_class_type) +//=========================================================================== + : Id_(0), classification_type_(CLASSIFICATION_UNDEF), + edge_class_type_(edge_class_type), + associated_sf_(0), associated_blend_(0), blend_edge_(0), surfflag_(NOT_SET), + surf_adaption_(INITIAL), mink1_(0.0), maxk1_(0.0), + mink2_(0.0), maxk2_(0.0), avH_(0.0), avK_(0.0), MAH_(0.0), MAK_(0.0), + frac_norm_in_(0.0), frac_norm_in2_(0.0), maxdist_(0.0), avdist_(0.0), + num_inside_(0), num_inside2_(0), + prev_region_(0), maxdist_base_(0.0), avdist_base_(0.0), num_in_base_(0), + visited_(false), to_be_removed_(false) +{ + domain_[0] = domain_[1] = domain_[2] = domain_[3] = 0.0; + bbox_ = BoundingBox(3); +} + +//=========================================================================== +RevEngRegion::RevEngRegion(int classification_type, int edge_class_type) +//=========================================================================== + : Id_(0), classification_type_(classification_type), + edge_class_type_(edge_class_type), + associated_sf_(0), associated_blend_(0), blend_edge_(0), surfflag_(NOT_SET), + surf_adaption_(INITIAL), mink1_(0.0), maxk1_(0.0), + mink2_(0.0), maxk2_(0.0), avH_(0.0), avK_(0.0), MAH_(0.0), MAK_(0.0), + frac_norm_in_(0.0), frac_norm_in2_(0.0), maxdist_(0.0), avdist_(0.0), + num_inside_(0), num_inside2_(0), + prev_region_(0), maxdist_base_(0.0), avdist_base_(0.0), num_in_base_(0), + visited_(false), to_be_removed_(false) +{ + domain_[0] = domain_[1] = domain_[2] = domain_[3] = 0.0; + bbox_ = BoundingBox(3); +} + +//=========================================================================== +RevEngRegion::RevEngRegion(int classification_type, + int edge_class_type, + vector<RevEngPoint*> & points) +//=========================================================================== + : Id_(0), group_points_(points), classification_type_(classification_type), + edge_class_type_(edge_class_type), associated_sf_(0), associated_blend_(0), + blend_edge_(0), surfflag_(NOT_SET), surf_adaption_(INITIAL), + avH_(0.0), avK_(0.0), MAH_(0.0), MAK_(0.0), + frac_norm_in_(0.0), frac_norm_in2_(0.0), maxdist_(0.0), avdist_(0.0), + num_inside_(0), num_inside2_(0), + prev_region_(0), maxdist_base_(0.0), avdist_base_(0.0), num_in_base_(0), + visited_(false), to_be_removed_(false) +{ + domain_[0] = domain_[1] = domain_[2] = domain_[3] = 0.0; + + for (size_t kj=0; kj<group_points_.size(); ++kj) + group_points_[kj]->setRegion(this); + + // Bounding box and principal curvature summary + maxk2_ = std::numeric_limits<double>::lowest(); + mink2_ = std::numeric_limits<double>::max(); + maxk1_ = std::numeric_limits<double>::lowest(); + mink1_ = std::numeric_limits<double>::max(); + bbox_ = BoundingBox(3); + double fac = 1.0/(double)group_points_.size(); + for (size_t kj=0; kj<group_points_.size(); ++kj) + { + double k1 = group_points_[kj]->minPrincipalCurvature(); + double k2 = group_points_[kj]->maxPrincipalCurvature(); + double H = group_points_[kj]->meanCurvature(); + double K = group_points_[kj]->GaussCurvature(); + mink1_ = std::min(mink1_, fabs(k1)); + maxk1_ = std::max(maxk1_, fabs(k1)); + mink2_ = std::min(mink2_, fabs(k2)); + maxk2_ = std::max(maxk2_, fabs(k2)); + avH_ += fac*H; + avK_ += fac*K; + MAH_ += fac*fabs(H); + MAK_ += fac*fabs(K); + Vector3D point = group_points_[kj]->getPoint(); + Point point2(point[0], point[1], point[2]); + bbox_.addUnionWith(point2); + } + + if (group_points_.size() > 0) + normalcone_ = DirectionCone(group_points_[0]->getLocFuncNormal()); + avnorm_ = Point(0.0, 0.0, 0.0); + if (group_points_.size() > 0) + normalcone2_ = DirectionCone(group_points_[0]->getTriangNormal()); + avnorm2_ = Point(0.0, 0.0, 0.0); + for (size_t kj=1; kj<group_points_.size(); ++kj) + { + Point norm = group_points_[kj]->getLocFuncNormal(); + normalcone_.addUnionWith(norm); + avnorm_ += fac*norm; + Point norm2 = group_points_[kj]->getTriangNormal(); + normalcone2_.addUnionWith(norm2); + avnorm2_ += fac*norm2; + } + // (void)avnorm_.normalize_checked(); + // (void)avnorm2_.normalize_checked(); +} + +//=========================================================================== +RevEngRegion::~RevEngRegion() +//=========================================================================== +{ + if (associated_blend_ != 0) + associated_blend_->removeBlendReg(this); + removeFromAdjacent(); + for (size_t ki=0; ki<rev_edges_.size(); ++ki) + { + rev_edges_[ki]->eraseAdjacent(this); + } + for (size_t ki=0; ki<associated_sf_.size(); ++ki) + associated_sf_[ki]->removeRegion(this); + int stop_break = 1; +} + +//=========================================================================== +void RevEngRegion::setAccuracy(double maxdist, double avdist, int num_inside, + int num_inside2) +//=========================================================================== +{ + maxdist_ = maxdist; + avdist_ = avdist; + num_inside_ = num_inside; + num_inside2_ = num_inside2; + +} + +//=========================================================================== +void RevEngRegion::joinToCurrent(double tol, double angtol, int small_lim, + vector<RevEngRegion*>& adapted_regions) +//=========================================================================== +{ + if (!hasSurface()) + return; + shared_ptr<ParamSurface> surf = getSurface(0)->surface(); + int classtype = surf->instanceType(); + bool cyllike = (classtype == Class_Cylinder || classtype == Class_Cone); + double small_frac = 0.1; + double tol_fac = 2.0; + +#ifdef DEBUG_GROW + std::ofstream of("master_reg.g2"); + writeRegionPoints(of); + writeSurface(of); +#endif + + vector<RevEngRegion*> adj_reg(adjacent_regions_.begin(), adjacent_regions_.end()); + + for (size_t ki=0; ki<adj_reg.size(); ++ki) + { + if (adj_reg[ki]->hasSurface()) + continue; // Not the correct grow method + if (adj_reg[ki]->hasAssociatedBlend()) + continue; + + +#ifdef DEBUG_GROW + std::ofstream ofn("added_region_cand.g2"); + adj_reg[ki]->writeRegionPoints(ofn); +#endif + + vector<RevEngPoint*> points = adj_reg[ki]->getPoints(); + int num_adj = (int)points.size(); + int num_curr = (int)group_points_.size(); + + // Check if the points can be approximated by the current surface + double maxd, avd; + int num_in, num2_in; + vector<RevEngPoint*> in, out; + vector<pair<double, double> > dist_ang; + vector<double> parvals; + RevEngUtils::distToSurf(points.begin(), points.end(), surf, tol, + maxd, avd, num_in, num2_in, + in, out, parvals, dist_ang, angtol); + + int num_ang_in = 0; + double avang = 0.0; + double nfac = 1.0/(double)num_adj; + for (size_t kh=0; kh<dist_ang.size(); ++kh) + { + avang += nfac*dist_ang[kh].second; + if (dist_ang[kh].second <= angtol) + num_ang_in++; + } + + int adj_sf_flag = adj_reg[ki]->defineSfFlag(0, tol, num_in, num2_in, + avd, cyllike); + + // Combined numbers + double maxd2 = std::max(maxdist_, maxd); + double avd2 = ((double)num_curr*avdist_ + (double)num_adj*avd)/ + (double)(num_curr+num_adj); + int num_in2 = num_inside_ + num_in; + int num2_in2 = num_inside2_ + num2_in; + int sf_flag2 = defineSfFlag(num_curr+num_adj, 0, tol, num2_in2, num_in2, + avd2, cyllike); + if (sf_flag2 <= surfflag_ && + (adj_sf_flag < ACCURACY_POOR || + (avd <= tol_fac*tol && num_adj < small_lim && + (double)num_adj < small_frac*(double)num_curr))) + { + vector<RevEngRegion*> added_adjacent; + includeAdjacentRegion(adj_reg[ki], maxd, avd, num_in, + num2_in, parvals, dist_ang, + added_adjacent); + adapted_regions.push_back(adj_reg[ki]); + setSurfaceFlag(sf_flag2); + } + } +#ifdef DEBUG_GROW + std::ofstream of2("updated_region.g2"); + writeRegionPoints(of2); +#endif + int stop_break = 1; +} + + + +//=========================================================================== +void RevEngRegion::joinRegions(Point mainaxis[3], double approx_tol, double anglim, + vector<RevEngRegion*>& adapted_regions) +//=========================================================================== +{ + if (group_points_.size() < 5) + return; + +#ifdef DEBUG_JOIN + std::ofstream of("region_grow.g2"); + writeRegionInfo(of); +#endif + + //double eps = 1.0e-6; + shared_ptr<ParamSurface> surf1; + double avdist1, maxdist1; + int num_in1, num2_in1; + if (basesf_.get()) + { + surf1 = basesf_; + getBaseDist(maxdist1, avdist1, num_in1, num2_in1); + } + else + { + surf1 = surfApprox(group_points_, bbox_); + vector<RevEngPoint*> in1, out1; + approximationAccuracy(group_points_, surf1, approx_tol, anglim, maxdist1, avdist1, + in1, out1); + num_in1 = (int)in1.size(); + } +#ifdef DEBUG_JOIN + std::ofstream of2("approx_sf.g2"); + surf1->writeStandardHeader(of2); + surf1->write(of2); +#endif + + if (num_in1 < (int)group_points_.size()/2 || avdist1 > approx_tol) + return; + + int kv=0; + int numfac = 10; + for (auto it=adjacent_regions_.begin(); it!=adjacent_regions_.end();) + { + ++kv; + if ((*it)->hasSurface()) + { + ++it; + continue; // Not the correct grow method + } + + if ((*it)->visited()) + { + ++it; + continue; + } + (*it)->setVisited(true); + + int num = (int)group_points_.size(); + int num2 = (*it)->numPoints(); + if (num2 > numfac*num) + { + ++it; + continue; + } + + auto itnext = it; + ++itnext; + +#ifdef DEBUG_JOIN + std::ofstream ofn("region_grow_cand.g2"); + (*it)->writeRegionInfo(ofn); +#endif + + vector<RevEngPoint*> points = (*it)->getPoints(); + + // Check if the points can be approximated by the current surface + double avdist2_0, maxdist2_0; + vector<RevEngPoint*> in2_0, out2_0; + approximationAccuracy(points, surf1, approx_tol, anglim, maxdist2_0, avdist2_0, + in2_0, out2_0); + int num_in2_0 = (int)in2_0.size(); + + // Compute overall numbers + int tot_num = (int)group_points_.size()+(int)points.size(); + double frac = (double)(num_in1+num_in2_0)/(double)(tot_num); + double avd = (avdist1*(double)group_points_.size() + + avdist2_0*(double)points.size())/(double)tot_num; + //if (in2_0.size() > points.size()/2 && avdist2_0 < approx_tol) + if (frac > 0.5 && avd < approx_tol) + { + // Include region in current + adapted_regions.push_back((*it)); + for (auto it2=(*it)->adjacent_regions_.begin(); + it2!=(*it)->adjacent_regions_.end(); ++it2) + { + if (*it2 != this) + { + addAdjacentRegion(*it2); + (*it2)->addAdjacentRegion(this); + (*it2)->removeAdjacentRegion(*it); + } + } + maxdist1 = std::max(maxdist1, maxdist2_0); + avdist1 = (num*avdist1 + num2*avdist2_0)/(double)(num+num2); + for (auto it3=(*it)->pointsBegin(); it3!=(*it)->pointsEnd(); ++it3) + (*it3)->addMove(); + vector<pair<double,double> > dummy; + addRegion((*it), dummy); + removeAdjacentRegion(*it); + it = itnext; + continue; + } + + + bool always_stop = true; + if (num2 < 5 || num2 > num || always_stop) + { + it = itnext; + continue; + } + + shared_ptr<ParamSurface> surf2; + + if (basesf_.get() && + ((!(*it)->basesf_.get()) || + ((*it)->basesf_.get() && + basesf_->instanceType() == (*it)->basesf_->instanceType()))) + { + vector<RevEngPoint*> all_pts; + all_pts.insert(all_pts.end(), group_points_.begin(), group_points_.end()); + all_pts.insert(all_pts.end(), points.begin(), points.end()); + if (basesf_->instanceType() == Class_Plane) + surf2 = computePlane(all_pts, avnorm_, mainaxis); + else if (basesf_->instanceType() == Class_Cylinder) + { + surf2 = computeCylinder(all_pts, approx_tol); + } + } + else + surf2 = surfApprox(points, (*it)->getBbox()); + + if (!surf2.get()) + { + it = itnext; + continue; + } + +#ifdef DEBUG_JOIN + std::ofstream of3("approx_sf2.g2"); + surf2->writeStandardHeader(of3); + surf2->write(of3); +#endif + + double avdist2, maxdist2; + vector<RevEngPoint*> in2, out2; + approximationAccuracy(points, surf2, approx_tol, anglim, + maxdist2, avdist2, in2, out2); + if (in2.size() < points.size()/2 && maxdist2 > approx_tol) + { + it = itnext; + continue; + } + int num_in2 = (int)in2.size(); + + vector<RevEngPoint*> mergept(group_points_.begin(), group_points_.end()); + mergept.insert(mergept.end(), (*it)->pointsBegin(), + (*it)->pointsEnd()); + BoundingBox bbox = bbox_; + bbox.addUnionWith((*it)->getBbox()); + + shared_ptr<SplineSurface> surf3 = surfApprox(mergept, bbox); +#ifdef DEBUG_JOIN + std::ofstream of4("approx_sf3.g2"); + surf3->writeStandardHeader(of4); + surf3->write(of4); +#endif + + double avdist3_0, maxdist3_0; + vector<RevEngPoint*> in3_0, out3_0; + approximationAccuracy(points, surf3, approx_tol, anglim, + maxdist3_0, avdist3_0, in3_0, out3_0); + if (in3_0.size() < points.size()/2 || avdist3_0 > approx_tol) + { + it = itnext; + continue; + } + + + double avdist3, maxdist3; + vector<RevEngPoint*> in3, out3; + approximationAccuracy(mergept, surf3, approx_tol, anglim, + maxdist3, avdist3, in3, out3); + int num_in3 = (int)in3.size(); + + if (/*maxdist3 <= 1.1*std::max(maxdist1, maxdist2) && */ + avdist3 <= 1.1*std::max(avdist1, avdist2) && avdist3 < approx_tol && + num_in3 > num_in1 && num_in3 > 3*(num_in1+num_in2)/4) + { + // Include region in current + adapted_regions.push_back((*it)); + for (auto it2=(*it)->adjacent_regions_.begin(); + it2!=(*it)->adjacent_regions_.end(); ++it2) + { + if (*it2 != this) + { + addAdjacentRegion(*it2); + (*it2)->addAdjacentRegion(this); + (*it2)->removeAdjacentRegion(*it); + } + } + maxdist1 = maxdist3; + avdist1 = avdist3; + for (auto it3=(*it)->pointsBegin(); it3!=(*it)->pointsEnd(); ++it3) + (*it3)->addMove(); + vector<pair<double,double> > dummy; + addRegion((*it), dummy); + removeAdjacentRegion(*it); + num_in1 = num_in3; + surf1 = surf3; + } + +#ifdef DEBUG_JOIN + std::ofstream ofl("region_grow2.g2"); + writeRegionInfo(ofl); +#endif + int stop_break = 1; + it = itnext; + } + + for (auto it=adjacent_regions_.begin(); it!=adjacent_regions_.end(); ++it) + (*it)->setVisited(false); + +} + + +//=========================================================================== +void RevEngRegion::approximationAccuracy(vector<RevEngPoint*>& points, + shared_ptr<ParamSurface> surf, + double tol, double angtol, + double& maxd, double& avd, + vector<RevEngPoint*>& in, + vector<RevEngPoint*>& out) +//=========================================================================== +{ + avd = maxd = 0.0; + double eps = 1.0e-6; + double wgt = 1.0/(double)points.size(); + for (size_t ki=0; ki<points.size(); ++ki) + { + Vector3D xyz = points[ki]->getPoint(); + Point pos(xyz[0], xyz[1], xyz[2]); + double upar, vpar, dist; + Point close; + surf->closestPoint(pos, upar, vpar, close, dist, eps); + avd += wgt*dist; + maxd = std::max(maxd, dist); + if (dist < tol) + { + Point normal; + surf->normal(normal, upar, vpar); + double ang = normal.angle(points[ki]->getLocFuncNormal()); + ang = std::min(ang, M_PI-ang); + if (ang < angtol) + in.push_back(points[ki]); + else + out.push_back(points[ki]); + } + else + out.push_back(points[ki]); + } +} + +//=========================================================================== +void RevEngRegion::splitPlanar(double lim_cone, int min_point_reg, + vector<vector<RevEngPoint*> >& other_groups, + vector<RevEngPoint*>& single) +//=========================================================================== +{ + vector<vector<RevEngPoint*> > groups; + vector<DirectionCone> cones; + for (size_t ki=0; ki<group_points_.size(); ++ki) + { + Point norm = group_points_[ki]->getTriangNormal(); + size_t kj; + for (kj=0; kj<cones.size(); ++kj) + { + double ang = cones[kj].unionAngle(norm); + if (ang <= lim_cone) + { + cones[kj].addUnionWith(norm); + groups[kj].push_back(group_points_[ki]); + break; + } + } + if (kj == cones.size()) + { + DirectionCone curr(norm); + cones.push_back(curr); + vector<RevEngPoint*> other; + other.push_back(group_points_[ki]); + groups.push_back(other); + } + } +#ifdef DEBUG_PLANAR + std::ofstream of("planar_groups.g2"); + for (size_t ki=0; ki<groups.size(); ++ki) + { + of << "400 1 0 4 100 155 0 255" << std::endl; + of << groups[ki].size() << std::endl; + for (size_t kj=0; kj<groups[ki].size(); ++kj) + of << groups[ki][kj]->getPoint() << std::endl; + } +#endif + if (groups.size() == 1) + return; + + vector<RevEngPoint*> remain; + for (int ka=(int)groups.size()-1; ka>=0; --ka) + { + if ((int)groups[ka].size() < min_point_reg) + { + remain.insert(remain.end(), groups[ka].begin(), groups[ka].end()); + groups.erase(groups.begin()+ka); + } + } + + size_t num_groups = groups.size(); + for (size_t ki=0; ki<num_groups; ++ki) + { + vector<vector<RevEngPoint*> > connected; + vector<RevEngPoint*> dummy; + connectedGroups(groups[ki], connected, false, dummy); + for (size_t kj=1; kj<connected.size(); ++kj) + if (connected[kj].size() > connected[0].size()) + std::swap(connected[kj], connected[0]); + + groups[ki] = connected[0]; + for (size_t kj=1; kj<connected.size(); ++kj) + { + if (connected[kj].size() >= min_point_reg) + groups.push_back(connected[kj]); + else + remain.insert(remain.end(), connected[kj].begin(), connected[kj].end()); + } + } + + for (size_t ki=1; ki<groups.size(); ++ki) + if (groups[ki].size() > groups[0].size()) + std::swap(groups[ki], groups[0]); + + std::swap(group_points_, groups[0]); + updateInfo(); + + if (groups.size() > 0) + other_groups.insert(other_groups.end(), groups.begin()+1, groups.end()); + + if (remain.size() > 0) + { + vector<vector<RevEngPoint*> > connected2; + vector<RevEngPoint*> dummy2; + connectedGroups(remain, connected2, false, dummy2); + for (size_t kj=0; kj<connected2.size(); ++kj) + { + if (connected2[kj].size() == 1) + { + connected2[kj][0]->unsetRegion(); + single.push_back(connected2[kj][0]); + } + else + other_groups.push_back(connected2[kj]); + } + } + int stop_break = 1; +} + +//=========================================================================== +void RevEngRegion::updateRegion(double approx_tol, double anglim, + vector<RevEngRegion*>& adapted_regions, + vector<shared_ptr<RevEngRegion> >& outdiv_regions) +//=========================================================================== +{ + if (group_points_.size() < 5) + return; + +#ifdef DEBUG_UPDATE + std::ofstream of("region_grow.g2"); + writeRegionInfo(of); +#endif + double eps = 1.0e-6; + shared_ptr<SplineSurface> surf = surfApprox(group_points_, bbox_); +#ifdef DEBUG_UPDATE + std::ofstream of2("approx_sf.g2"); + surf->writeStandardHeader(of2); + surf->write(of2); +#endif + // Check if the accuracy is sufficient as a basis for growth + double avdist = 0.0, maxdist = 0.0; + vector<RevEngPoint*> in, out; + approximationAccuracy(group_points_, surf, approx_tol, anglim, maxdist, avdist, + in, out); + if (in.size() < group_points_.size()/2 || avdist > approx_tol) + return; + + setBaseSf(surf, maxdist, avdist, (int)in.size(), (int)in.size()); + + // Grow + vector<RevEngPoint*> visited; + int numpt = (int)group_points_.size(); + int numfac = 10; + // std::set<RevEngPoint*> tmpset0(in.begin(), in.end()); + // if (tmpset0.size() != in.size()) + // std::cout << "Point number mismatch, init. " << tmpset0.size() << " " << in.size() << std::endl; + size_t ki = 0; + for (int ka=0; ka<10; ++ka) + { + size_t in_size = in.size(); + for (; ki<in.size(); ++ki) + { + vector<ftSamplePoint*> next = in[ki]->getNeighbours(); + for (size_t kj=0; kj<next.size(); ++kj) + { + RevEngPoint *curr = dynamic_cast<RevEngPoint*>(next[kj]); + if (curr->moved()) + continue; // Already in an extended region + if (curr->isEdge(edge_class_type_)) + continue; // Do not include points labelled as edge + if (curr->region() == this) + continue; + if (curr->visited()) + continue; + + // if (std::find(in.begin(), in.end(), curr) != in.end()) + // { + // std::cout << "Double point" << curr << std::endl; + // } + curr->setVisited(); + visited.push_back(curr); + int numpt2 = 0; + if (curr->region()) + numpt2 = curr->region()->numPoints(); + if (numpt2 > numfac*numpt) + continue; + Vector3D xyz = curr->getPoint(); + Point pos(xyz[0], xyz[1], xyz[2]); + double upar, vpar, dist; + Point close; + surf->closestPoint(pos, upar, vpar, close, dist, eps); + if (dist < approx_tol) + { + Point normal; + surf->normal(normal, upar, vpar); + double ang = normal.angle(curr->getLocFuncNormal()); + ang = std::min(ang, M_PI-ang); + if (ang < anglim) + in.push_back(curr); + else + out.push_back(curr); + } + else + out.push_back(curr); + } + } +#ifdef DEBUG_UPDATE + std::ofstream of3("in_out.g2"); + of3 << "400 1 0 4 255 0 0 255" << std::endl; + of3 << in.size() << std::endl; + for (size_t kj=0; kj<in.size(); ++kj) + of3 << in[kj]->getPoint() << std::endl; + of3 << "400 1 0 4 0 255 0 255" << std::endl; + of3 << out.size() << std::endl; + for (size_t kj=0; kj<out.size(); ++kj) + of3 << out[kj]->getPoint() << std::endl; +#endif + if (in.size() == in_size) + break; + + vector<RevEngPoint*> in_out(in.begin(), in.end()); + in_out.insert(in_out.end(), out.begin(), out.end()); + shared_ptr<SplineSurface> surf2 = surfApprox(in_out, bbox_); +#ifdef DEBUG_UPDATE + std::ofstream of4("approx_sf2.g2"); + surf2->writeStandardHeader(of4); + surf2->write(of4); +#endif + //int nmb_in2 = 0; + double avdist2 = 0.0; + double maxdist2 = 0.0; + in.clear(); + out.clear(); + double wgt = 1.0/(double)in_out.size(); + for (size_t ki=0; ki<in_out.size(); ++ki) + { + Vector3D xyz = in_out[ki]->getPoint(); + Point pos(xyz[0], xyz[1], xyz[2]); + double upar, vpar, dist; + Point close; + surf2->closestPoint(pos, upar, vpar, close, dist, eps); + avdist2 += wgt*dist; + maxdist2 = std::max(maxdist2,dist); + if (dist < approx_tol) + { + Point normal; + surf2->normal(normal, upar, vpar); + double ang = normal.angle(in_out[ki]->getLocFuncNormal()); + ang = std::min(ang, M_PI-ang); + if (ang < anglim) + in.push_back(in_out[ki]); + else + out.push_back(in_out[ki]); + } + else + out.push_back(in_out[ki]); + } + + if (in.size() < out.size() || avdist2 > approx_tol) + { + break; + } + + setBaseSf(surf2, maxdist2, avdist2, (int)in.size(), (int)in.size()); + surf = surf2; + // std::set<RevEngPoint*> tmpset(in.begin(), in.end()); + // if (tmpset.size() != in.size()) + // std::cout << "Point number mismatch. " << ka << " " << tmpset.size() << " " << in.size() << std::endl; + int stop_break0 = 1; + } + + //std::cout << "Ready to move points " << std::endl; + // Move in points + set<RevEngRegion*> affected_reg; + for (size_t ki=0; ki<in.size(); ++ki) + { + in[ki]->setMoved(); + + if (in[ki]->region() == this) + continue; + + RevEngRegion *other_reg = in[ki]->region(); + if (other_reg) + { + other_reg->removePoint(in[ki]); + affected_reg.insert(other_reg); + } + in[ki]->setRegion(this); + in[ki]->addMove(); + group_points_.push_back(in[ki]); + } + + for (size_t ki=0; ki<visited.size(); ++ki) + visited[ki]->unsetVisited(); + + vector<RevEngRegion*> affected_reg2(affected_reg.begin(), affected_reg.end()); + for (size_t ki=0; ki<affected_reg2.size(); ++ki) + { + if (affected_reg2[ki]->numPoints() == 0) + { + for (auto it=affected_reg2[ki]->adjacent_regions_.begin(); + it!=affected_reg2[ki]->adjacent_regions_.end(); ++it) + { + // if ((*it) != this) + // { + // addAdjacentRegion(*it); + (*it)->removeAdjacentRegion(affected_reg2[ki]); + // } + } + // removeAdjacentRegion(affected_reg2[ki]); + adapted_regions.push_back(affected_reg2[ki]); + } + else + { + vector<vector<RevEngPoint*> > separate_groups; + affected_reg2[ki]->splitRegion(separate_groups); + int classtype = affected_reg2[ki]->getClassificationType(); + for (size_t ki=0; ki<separate_groups.size(); ++ki) + { + shared_ptr<RevEngRegion> reg(new RevEngRegion(classtype, + edge_class_type_, + separate_groups[ki])); + outdiv_regions.push_back(reg); + } + affected_reg2[ki]->updateInfo(approx_tol, anglim); + } + } + + updateInfo(approx_tol, anglim); + int stop_break = 1; + +} + +//=========================================================================== +bool RevEngRegion::segmentByPlaneAxis(Point mainaxis[3], int min_point_in, + int min_pt_reg, + double tol, double angtol, int prefer_elementary, + vector<RevEngRegion*>& adj_planar, + vector<shared_ptr<HedgeSurface> >& hedgesfs, + vector<shared_ptr<RevEngRegion> >& added_reg, + vector<HedgeSurface*>& prevsfs, + vector<vector<RevEngPoint*> >& added_groups) +//=========================================================================== +{ +#ifdef DEBUG_SEGMENT + std::ofstream of("adj_planar.g2"); + for (size_t ki=0; ki<adj_planar.size(); ++ki) + adj_planar[ki]->writeRegionPoints(of); +#endif + vector<pair<shared_ptr<ElementarySurface>, RevEngRegion*> > adj_elem(adj_planar.size()); + for (size_t ki=0; ki<adj_planar.size(); ++ki) + { + if (!adj_planar[ki]->hasSurface()) + return false; + shared_ptr<ParamSurface> surf = adj_planar[ki]->getSurface(0)->surface(); + shared_ptr<ElementarySurface> elemsf = + dynamic_pointer_cast<Plane,ParamSurface>(surf); + if (!elemsf.get()) + return false; + adj_elem[ki] = std::make_pair(elemsf, adj_planar[ki]); + } + + // Get candidate axis directions + vector<Point> dir; + size_t kr; + for (size_t ki=0; ki<adj_elem.size(); ++ki) + { + Point dir1 = adj_elem[ki].first->direction(); + for (kr=0; kr<dir.size(); ++kr) + { + double ang = dir[kr].angle(dir1); + ang = std::min(ang, M_PI-ang); + if (ang <= angtol) + break; + } + if (kr == dir.size()) + dir.push_back(dir1); + for (size_t kj=ki+1; kj<adj_elem.size(); ++kj) + { + Point dir2 = adj_elem[kj].first->direction(); + double ang = dir1.angle(dir2); + ang = std::min(ang, M_PI-ang); + if (ang > angtol) + { + Point dir3 = dir1.cross(dir2); + for (kr=0; kr<dir.size(); ++kr) + { + ang = dir[kr].angle(dir3); + ang = std::min(ang, M_PI-ang); + if (ang <= angtol) + break; + } + if (kr == dir.size()) + dir.push_back(dir3); + } + } + } + + vector<vector<RevEngPoint*> > group1, group2; + vector<RevEngPoint*> remaining; + double axisang = 0.1*M_PI; + double planeang = 0.05; + bool divided = sortByAxis(dir, tol, axisang, planeang, group1, group2, remaining); + + vector<RevEngPoint*> all; + for (size_t ki=0; ki<group1.size(); ++ki) + all.insert(all.end(), group1[ki].begin(), group1[ki].end()); + for (size_t ki=0; ki<group2.size(); ++ki) + all.insert(all.end(), group2[ki].begin(), group2[ki].end()); + all.insert(all.end(), remaining.begin(), remaining.end()); + std::set<RevEngPoint*> tmpset1(all.begin(), all.end()); + if (tmpset1.size() != all.size()) + std::cout << "Point number mismatch, all. " << tmpset1.size() << " " << all.size() << " " << group_points_.size() << std::endl; + + vector<RevEngPoint*> remain1; + bool found1 = integratePlanarPoints(dir, group1, adj_elem, tol, angtol, + remain1); + std::set<RevEngPoint*> tmpset2(remain1.begin(), remain1.end()); + if (tmpset2.size() != remain1.size()) + std::cout << "Point number mismatch, remain1. " << tmpset2.size() << " " << remain1.size() << std::endl; + +#ifdef DEBUG_SEGMENT + std::ofstream ofr1("remain1.g2"); + ofr1 << "400 1 0 4 50 155 50 255" << std::endl; + ofr1 << remain1.size() << std::endl; + for (size_t ki=0; ki<remain1.size(); ++ki) + ofr1 << remain1[ki]->getPoint() << std::endl; +#endif + + if (remain1.size() > 0) + remaining.insert(remaining.end(), remain1.begin(), remain1.end()); + + std::set<RevEngPoint*> tmpset3(remaining.begin(), remaining.end()); + if (tmpset3.size() != remaining.size()) + std::cout << "Point number mismatch, remaining2. " << tmpset3.size() << " " << remaining.size() << std::endl; + +#ifdef DEBUG_SEGMENT + std::ofstream of2("adj_planar2.g2"); + for (size_t ki=0; ki<adj_planar.size(); ++ki) + adj_planar[ki]->writeRegionPoints(of2); +#endif + + vector<RevEngPoint*> remain2; + bool found2 = defineCylindricalRegs(mainaxis, group2, min_point_in, + min_pt_reg, tol, angtol, + added_reg, hedgesfs, remain2); + std::set<RevEngPoint*> tmpset4(remain2.begin(), remain2.end()); + if (tmpset4.size() != remain2.size()) + std::cout << "Point number mismatch, remain2. " << tmpset4.size() << " " << remain2.size() << std::endl; + +#ifdef DEBUG_SEGMENT + std::ofstream ofr2("remain2.g2"); + ofr2 << "400 1 0 4 50 50 155 255" << std::endl; + ofr2 << remain2.size() << std::endl; + for (size_t ki=0; ki<remain2.size(); ++ki) + ofr2 << remain2[ki]->getPoint() << std::endl; +#endif + if (remain2.size() > 0) + remaining.insert(remaining.end(), remain2.begin(), remain2.end()); + + std::set<RevEngPoint*> tmpset5(remaining.begin(), remaining.end()); + if (tmpset5.size() != remaining.size()) + std::cout << "Point number mismatch, remaining3. " << tmpset5.size() << " " << remaining.size() << std::endl; + + std::vector<RevEngPoint*> dummy; + connectedGroups(remaining, added_groups, false, dummy); + int max_num = 0; + int max_ix = -1; + for (size_t ki=0; ki<added_groups.size(); ++ki) + if ((int)added_groups[ki].size() > max_num) + { + max_num = (int)added_groups[ki].size(); + max_ix = (int)ki; + } + + if (max_ix >= 0) + { + std::swap(group_points_, added_groups[max_ix]); + std::swap(added_groups[max_ix], added_groups[added_groups.size()-1]); + added_groups.pop_back(); + updateInfo(tol, angtol); + } + +#ifdef DEBUG_SEGMENT + std::ofstream of3("added_reg_surf.g2"); + for (size_t ki=0; ki<added_reg.size(); ++ki) + { + added_reg[ki]->writeRegionPoints(of3); + if (added_reg[ki]->hasSurface()) + added_reg[ki]->writeSurface(of3); + } +#endif + return (added_reg.size() > 0);//(found1 || found2); +} + +//=========================================================================== +bool RevEngRegion::defineCylindricalRegs(Point mainaxis[3], + vector<vector<RevEngPoint*> >& groups, + int min_point, int min_pt_reg, + double tol, double angtol, + vector<shared_ptr<RevEngRegion> >& added_reg, + vector<shared_ptr<HedgeSurface> >& hedgesfs, + vector<RevEngPoint*>& remaining) +//=========================================================================== +{ + bool found = false; + vector<HedgeSurface*> prevsfs; // Not feasible + for (size_t ki=0; ki<groups.size(); ++ki) + { + if (groups[ki].size() == 0) + continue; + + std::set<RevEngPoint*> tmpset4(groups[ki].begin(), groups[ki].end()); + if (tmpset4.size() != groups[ki].size()) + std::cout << "Point number mismatch, axis group " << ki << " " << tmpset4.size() << " " << groups[ki].size() << std::endl; + // Split into connected groups + vector<vector<RevEngPoint*> > connected; + std::vector<RevEngPoint*> dummy; + connectedGroups(groups[ki], connected, false, dummy); + for (size_t kj=0; kj<connected.size(); ++kj) + { + // Identify adjacent regions + std::set<RevEngRegion*> adj_reg; + for (size_t kr=0; kr<connected[kj].size(); ++kr) + { + vector<ftSamplePoint*> next = connected[kj][kr]->getNeighbours(); + for (size_t kh=0; kh<next.size(); ++kh) + { + RevEngPoint *curr = dynamic_cast<RevEngPoint*>(next[kh]); + RevEngRegion *adj = curr->region(); + if (adj && adj != this) + adj_reg.insert(adj); + } + } + + vector<pair<shared_ptr<ElementarySurface>, RevEngRegion*> > adj_elem; + for (auto it=adj_reg.begin(); it!=adj_reg.end(); ++it) + { + if ((*it)->hasSurface()) + { + shared_ptr<ParamSurface> surf = (*it)->getSurface(0)->surface(); + shared_ptr<ElementarySurface> elemsf = + dynamic_pointer_cast<ElementarySurface,ParamSurface>(surf); + if (elemsf.get()) + adj_elem.push_back(std::make_pair(elemsf, (*it))); + } + } + + if (adj_elem.size() > 1) + { + // Try to fit a cylinder from context + shared_ptr<RevEngRegion> tmp_reg(new RevEngRegion(classification_type_, + edge_class_type_, + connected[kj])); +#ifdef DEBUG_SEGMENT + std::ofstream of("cylinder_cand.g2"); + tmp_reg->writeRegionPoints(of); +#endif + vector<vector<RevEngPoint*> > added_groups; + bool found1 = tmp_reg->contextCylinder(mainaxis, tol, min_point, + min_pt_reg, angtol, 0, + adj_elem, hedgesfs, prevsfs, + added_groups); + + for (size_t kr=0; kr<added_groups.size(); ++kr) + { + for (size_t kh=0; kh<added_groups[kr].size(); ++kh) + added_groups[kr][kh]->setRegion(this); + remaining.insert(remaining.end(), added_groups[kr].begin(), + added_groups[kr].end()); + } + + if (found1) + { + found = true; + tmp_reg->setRegionAdjacency(); + added_reg.push_back(tmp_reg); + } + else + { + vector<RevEngPoint*> curr_points(tmp_reg->pointsBegin(), + tmp_reg->pointsEnd()); + for (size_t kh=0; kh<curr_points.size(); ++kh) + curr_points[kh]->setRegion(this); + remaining.insert(remaining.end(), curr_points.begin(), + curr_points.end()); + } + } + else + remaining.insert(remaining.end(), connected[kj].begin(), + connected[kj].end()); + } + } + + return found; +} + +//=========================================================================== +bool RevEngRegion::integratePlanarPoints(vector<Point>& dir, + vector<vector<RevEngPoint*> >& groups, + vector<pair<shared_ptr<ElementarySurface>,RevEngRegion*> >& adj_elem, + double tol, double angtol, + vector<RevEngPoint*>& remaining) +//=========================================================================== +{ + bool found = false; + for (size_t ki=0; ki<groups.size(); ++ki) + { + if (groups[ki].size() == 0) + continue; + + // Split into connected groups + vector<vector<RevEngPoint*> > connected; + std::vector<RevEngPoint*> dummy; + connectedGroups(groups[ki], connected, false, dummy); + for (size_t kj=0; kj<connected.size(); ++kj) + { + // Identify compatible adjacent plane + std::set<RevEngRegion*> adj_reg; + for (size_t kr=0; kr<connected[kj].size(); ++kr) + { + vector<ftSamplePoint*> next = connected[kj][kr]->getNeighbours(); + for (size_t kh=0; kh<next.size(); ++kh) + { + RevEngPoint *curr = dynamic_cast<RevEngPoint*>(next[kh]); + RevEngRegion *adj = curr->region(); + if (adj != this) + adj_reg.insert(adj); + } + } + + bool integrated = false; + for (auto it=adj_reg.begin(); it!=adj_reg.end(); ++it) + { + for (size_t kr=0; kr<adj_elem.size(); ++kr) + { + if (adj_elem[kr].second == (*it)) + { + Point curr_dir = dir[ki/2]; + if (ki%2 == 0) + curr_dir *= -1; + Point norm = adj_elem[kr].first->direction(); + Point vec = adj_elem[kr].second->getMeanNormal(); + if (norm*vec < 0.0) + norm *= -1; + double ang = curr_dir.angle(norm); + if (ang < angtol) + { + // Check distance + Point loc = adj_elem[kr].first->location(); + //double avdist = 0.0; + shared_ptr<ParamSurface> surf = adj_elem[kr].first; + double maxd, avd; + int nmb_in, nmb2_in; + vector<RevEngPoint*> in, out; + vector<pair<double,double> > dist_ang; + vector<double> parvals; + RevEngUtils::distToSurf(connected[kj].begin(), connected[kj].end(), + surf, tol, maxd, avd, nmb_in, nmb2_in, + in, out, parvals, dist_ang, angtol); + if (avd <= tol) + { + // Integrate group in adjacent plane + for (size_t kh=0; kh<connected[kj].size(); ++kh) + { + connected[kj][kh]->setPar(Vector2D(parvals[2*kh], + parvals[2*kh+1])); + connected[kj][kh]->setSurfaceDist(dist_ang[kh].first, + dist_ang[kh].second); + adj_elem[kr].second->addPoint(connected[kj][kh]); + } + integrated = true; + break; + } + } + } + if (integrated) + break; + } + if (integrated) + break; + } + + if (integrated) + found = true; + else + remaining.insert(remaining.end(), connected[kj].begin(), connected[kj].end()); + } + } + return found; +} + +//=========================================================================== +void RevEngRegion::growPlaneOrCyl(Point mainaxis[3], int min_pt_reg, + double tol, double angtol, + vector<RevEngRegion*>& grown_regions, + vector<HedgeSurface*>& adj_surfs, + vector<vector<RevEngPoint*> >& added_groups) +//=========================================================================== +{ + if (associated_sf_.size() == 0) + return; // No surface from which to grow + + int sfcode; + ClassType classtype = associated_sf_[0]->instanceType(sfcode); + if (classtype != Class_Plane && classtype != Class_Cylinder && + classtype != Class_Cone) + return; + + if (surfflag_ != ACCURACY_OK) + return; // Grow only surfaces with good accuracy + + vector<RevEngRegion*> adj_reg; + adj_reg.insert(adj_reg.end(), adjacent_regions_.begin(), adjacent_regions_.end()); + int num_points = (int)group_points_.size(); + for (size_t ki=0; ki<adj_reg.size(); ++ki) + { + // Get seed points + vector<RevEngPoint*> adj_pts = + adj_reg[ki]->extractNextToAdjacent(this); + + // Grow + growFromNeighbour(mainaxis, min_pt_reg, adj_pts, tol, + angtol, adj_reg[ki], false); + if (adj_reg[ki]->numPoints() == 0) + { + for (auto it=adj_reg[ki]->adjacent_regions_.begin(); + it != adj_reg[ki]->adjacent_regions_.end(); ++it) + (*it)->removeAdjacentRegion(adj_reg[ki]); + if (adj_reg[ki]->hasSurface()) + { + int num_sf = adj_reg[ki]->numSurface(); + for (int kb=0; kb<num_sf; ++kb) + adj_surfs.push_back(adj_reg[ki]->getSurface(kb)); + } + removeAdjacentRegion(adj_reg[ki]); + grown_regions.push_back(adj_reg[ki]); + } + else + { + // Make sure that the adjacent region is connected + vector<vector<RevEngPoint*> > separate_groups; + adj_reg[ki]->splitRegion(separate_groups); + if (separate_groups.size() > 0) + { + added_groups.insert(added_groups.end(), separate_groups.begin(), + separate_groups.end()); + if (adj_reg[ki]->hasSurface()) + adj_reg[ki]->checkReplaceSurf(mainaxis, min_pt_reg, tol, + angtol); + } + } + } + if ((int)group_points_.size() > num_points) + checkReplaceSurf(mainaxis, min_pt_reg, tol, angtol); + +#ifdef DEBUG_GROWNEIGHBOUR + std::ofstream of("grown_group.g2"); + writeRegionPoints(of); +#endif + if (false) //(int)group_points_.size() > num_points) + { + // Compute distance + shared_ptr<ParamSurface> surf = getSurface(0)->surface(); + double maxdist, avdist; + int num_in, num2_in; + vector<pair<double, double> > dist_ang; + vector<double> parvals; + vector<RevEngPoint*> inpt, outpt; + RevEngUtils::distToSurf(group_points_.begin(), group_points_.end(), + surf, tol, maxdist, avdist, num_in, num2_in, + inpt, outpt, parvals, dist_ang, angtol); + + int sf_flag = defineSfFlag(0, tol, num_in, num2_in, + avdist, (classtype == Class_Cylinder)); + for (size_t kh=0; kh<group_points_.size(); ++kh) + { + group_points_[kh]->setPar(Vector2D(parvals[2*kh],parvals[2*kh+1])); + group_points_[kh]->setSurfaceDist(dist_ang[kh].first, dist_ang[kh].second); + } + setAccuracy(maxdist, avdist, num_in, num2_in); + setSurfaceFlag(sf_flag); + checkReplaceSurf(mainaxis, min_pt_reg, tol, angtol); + } +} + +//=========================================================================== +bool RevEngRegion::segmentByAdjSfContext(Point mainaxis[3], int min_point_in, + int min_pt_reg, double tol, double angtol, + vector<RevEngRegion*>& adj_planar, + vector<vector<RevEngPoint*> >& added_groups) +//=========================================================================== +{ +#ifdef DEBUG_SEGMENT + std::ofstream of("adj_planar.g2"); + for (size_t ki=0; ki<adj_planar.size(); ++ki) + adj_planar[ki]->writeRegionPoints(of); +#endif + //double lim = 0.1; + int num_pt = numPoints(); + for (size_t ki=0; ki<adj_planar.size(); ++ki) + { + if ((double)adj_planar[ki]->numPoints() > min_point_in/*lim*num_pt*/) + { + // Get seed points + vector<RevEngPoint*> adj_pts = extractNextToAdjacent(adj_planar[ki]); + + // Grow adjacent + adj_planar[ki]->growFromNeighbour(mainaxis, min_pt_reg, + adj_pts, tol, angtol, this); + } +#ifdef DEBUG_SEGMENT + std::ofstream of2("updated_planar.g2"); + writeRegionInfo(of2); + adj_planar[ki]->writeRegionPoints(of2); +#endif + } + if (numPoints() > 0 && numPoints() != num_pt) + { + splitRegion(added_groups); + updateInfo(tol, angtol); + updateRegionAdjacency(); +// #ifdef DEBUG_SEGMENT +// if (!isConnected()) +// std::cout << "Disconnect, segmentByAdjSfContext" << std::endl; +// #endif + return (numPoints() > num_pt/10) ? true : false; + //return true; + } + else if (numPoints() == 0) + { + removeFromAdjacent(); + clearRegionAdjacency(); + } + + return false; +} + +//=========================================================================== +bool RevEngRegion::segmentByDirectionContext(int min_point_in, double tol, + const Point& dir, double angtol, + vector<vector<RevEngPoint*> >& added_groups) +//=========================================================================== +{ + double pihalf = 0.5*M_PI; + vector<vector<RevEngPoint*> > pnt_groups(3); + for (size_t ki=0; ki<group_points_.size(); ++ki) + { + Point norm = group_points_[ki]->getLocFuncNormal(); + double ang = dir.angle(norm); + ang = std::min(ang, M_PI-ang); + if (ang < angtol) + pnt_groups[0].push_back(group_points_[ki]); + else if (fabs(pihalf-ang) < angtol) + pnt_groups[1].push_back(group_points_[ki]); + else + pnt_groups[2].push_back(group_points_[ki]); + } + + int num_pnt_groups = (pnt_groups[0].size() > 0) + (pnt_groups[1].size() > 0) + + (pnt_groups[2].size() > 0); + if (num_pnt_groups <= 1) + return false; +#ifdef DEBUG_SEGMENT + std::ofstream of("point_groups.g2"); + for (int ka=0; ka<3; ++ka) + { + if (pnt_groups[ka].size() > 0) + { + of << "400 1 0 0" << std::endl; + of << pnt_groups[ka].size() << std::endl; + for (size_t ki=0; ki<pnt_groups[ka].size(); ++ki) + of << pnt_groups[ka][ki]->getPoint() << std::endl; + } + } +#endif + vector<vector<RevEngPoint*> > sep_groups; + size_t g_ix = 0; + for (int ka=0; ka<3; ++ka) + { + if (pnt_groups[ka].size() > 1) + { + shared_ptr<RevEngRegion> reg(new RevEngRegion(classification_type_, + edge_class_type_, + pnt_groups[ka])); + vector<vector<RevEngPoint*> > curr_sep_groups; + reg->splitRegion(curr_sep_groups); + sep_groups.push_back(reg->getPoints()); + if (curr_sep_groups.size() > 0) + sep_groups.insert(sep_groups.end(), curr_sep_groups.begin(), + curr_sep_groups.end()); + for (; g_ix<sep_groups.size(); ++g_ix) + for (size_t kj=0; kj<sep_groups[g_ix].size(); ++kj) + sep_groups[g_ix][kj]->unsetRegion(); + } + else if (pnt_groups[ka].size() == 1) + pnt_groups[ka][0]->unsetRegion(); + } + +#ifdef DEBUG_SEGMENT + std::ofstream of2("sep_groups.g2"); + for (size_t kj=0; kj<sep_groups.size(); ++kj) + { + of2 << "400 1 0 0" << std::endl; + of2 << sep_groups[kj].size() << std::endl; + for (size_t ki=0; ki<sep_groups[kj].size(); ++ki) + of2 << sep_groups[kj][ki]->getPoint() << std::endl; + } +#endif + + int max_ix = -1; + int num_pnts = 0; + for (size_t ki=0; ki<sep_groups.size(); ++ki) + { + if ((int)sep_groups[ki].size() > num_pnts) + { + num_pnts = (int)sep_groups[ki].size(); + max_ix = (int)ki; + } + } + + for (size_t ki=0; ki<sep_groups.size(); ++ki) + { + if ((int)ki == max_ix) + { + group_points_.clear(); + group_points_ = sep_groups[max_ix]; + for (size_t kj=0; kj<group_points_.size(); ++kj) + group_points_[kj]->setRegion(this); + updateInfo(tol, angtol); + } + else + { + for (size_t kj=0; kj<sep_groups[ki].size(); ++kj) + sep_groups[ki][kj]->unsetRegion(); + added_groups.push_back(sep_groups[ki]); + } + } + + return (added_groups.size() > 0); +} + +//=========================================================================== +void RevEngRegion::getPCA(double lambda[3], Point& eigen1, Point& eigen2, + Point& eigen3) +//=========================================================================== +{ + return getPCA(group_points_, lambda, eigen1, eigen2, eigen3); +} + +//=========================================================================== +void RevEngRegion::getPCA(vector<RevEngPoint*>& points, double lambda[3], + Point& eigen1, Point& eigen2, Point& eigen3) +//=========================================================================== +{ + // PCA analysis of group points + Vector3D xyz = points[0]->getPoint(); + Point pos0(xyz[0], xyz[1], xyz[2]); + vector<Point> pnts; + pnts.reserve(points.size()); + //double wgt = 1.0/(double)points.size(); + for (size_t ki=1; ki<points.size(); ++ki) + { + xyz = points[ki]->getPoint(); + Point pos(xyz[0], xyz[1], xyz[2]); + pnts.push_back(pos); + } + + double eigenvec[3][3]; + RevEngUtils::principalAnalysis(pos0, pnts, lambda, eigenvec); + eigen1 = Point(eigenvec[0][0], eigenvec[0][1], eigenvec[0][2]); + eigen2 = Point(eigenvec[1][0], eigenvec[1][1], eigenvec[1][2]); + eigen3 = Point(eigenvec[2][0], eigenvec[2][1], eigenvec[2][2]); +} + + +//=========================================================================== +shared_ptr<SplineSurface> RevEngRegion::surfApprox(vector<RevEngPoint*>& points, + const BoundingBox& bbox) +//=========================================================================== +{ + // PCA analysis of given points to orient plane for parametrerization + Vector3D xyz = points[0]->getPoint(); + Point pos0(xyz[0], xyz[1], xyz[2]); + vector<Point> pnts; + pnts.reserve(points.size()); + Point vec(0.0, 0.0, 0.0); + double wgt = 1.0/(double)(group_points_.size()); + for (size_t ki=1; ki<points.size(); ++ki) + { + Vector3D xyz = points[ki]->getPoint(); + Point pos(xyz[0], xyz[1], xyz[2]); + pnts.push_back(pos); + Point vec0 = points[ki]->minCurvatureVec(); + if (vec0*vec < 0.0) + vec0 *= -1; + vec += wgt*vec0; + } + double lambda[3]; + double eigenvec[3][3]; + RevEngUtils::principalAnalysis(pos0, pnts, lambda, eigenvec); + Point eigen3(eigenvec[2][0], eigenvec[2][1], eigenvec[2][2]); + Point ydir = eigen3.cross(vec); + ydir.normalize_checked(); + Point xdir = ydir.cross(eigen3); + xdir.normalize_checked(); + + // Parameterize points based on planar surface + pnts.push_back(pos0); + vector<double> data; + vector<double> param; + RevEngUtils::parameterizeWithPlane(pnts, bbox, xdir, ydir, + data, param); + + // Surface approximation + int order = 3; + double belt = 0.1*bbox.low().dist(bbox.high()); + shared_ptr<SplineSurface> surf = RevEngUtils::surfApprox(data, 3, param, order, + order, order, order, belt); +return surf; +} + +//=========================================================================== +void RevEngRegion::collect(RevEngPoint *pt, RevEngRegion *prev) +//=========================================================================== +{ + if (pt->hasRegion() && pt->region() != this) + return; // Cannot grow + group_points_.push_back(pt); + if (classification_type_ == CLASSIFICATION_UNDEF) + return; // Cannot grow + int type = pt->surfaceClassification(classification_type_); + double meancurv = pt->meanCurvature(); + double gausscurv = pt->GaussCurvature(); + if (type == C1_UNDEF) // SI_UNDEF == C1_UNDEF + return; // Cannot grow + + vector<RevEngPoint*> grouped; + grouped.push_back(pt); + Vector3D xyz = pt->getPoint(); + Point xyz2(xyz[0], xyz[1], xyz[2]); + bbox_.addUnionWith(xyz2); + if (normalcone_.dimension() == 0) + normalcone_ = DirectionCone(pt->getLocFuncNormal()); + else + normalcone_.addUnionWith(pt->getLocFuncNormal()); + if (normalcone2_.dimension() == 0) + normalcone2_ = DirectionCone(pt->getTriangNormal()); + else + normalcone2_.addUnionWith(pt->getTriangNormal()); + bool planar = planartype(); + for (size_t kj=0; kj<grouped.size(); ++kj) + { + vector<ftSamplePoint*> next = grouped[kj]->getNeighbours(); + for (size_t ki=0; ki<next.size(); ++ki) + { + RevEngPoint *curr = dynamic_cast<RevEngPoint*>(next[ki]); + if (!curr) + continue; // Should not happen + if (curr->isOutlier()) + continue; + if (curr->hasRegion() && curr->region() != prev) + continue; // Already belonging to a segment + if (curr->isEdge(edge_class_type_)) + continue; // An edge point + int type2 = curr->surfaceClassification(classification_type_); + if (type2 != type) + continue; // Different classification + if (classification_type_ == CLASSIFICATION_SHAPEINDEX && + (!planar) && meancurv*curr->meanCurvature() < 0.0) + continue; // Not compatible with one primary surface + double curv1 = meancurv*gausscurv; + double curv2 = curr->meanCurvature()*curr->GaussCurvature(); + if (classification_type_ == CLASSIFICATION_SHAPEINDEX && + (!planar) && curv1*curv2 < 0.0) + continue; // Not compatible with one primary surface + + // Add to region + curr->setRegion(this); + group_points_.push_back(curr); + xyz = curr->getPoint(); + xyz2 = Point(xyz[0], xyz[1], xyz[2]); + bbox_.addUnionWith(xyz2); + normalcone_.addUnionWith(curr->getLocFuncNormal()); + normalcone2_.addUnionWith(curr->getTriangNormal()); + + // Continue growing from this point + grouped.push_back(curr); + } + } +#ifdef DEBUG_COLLECT + std::ofstream of("collected_group.g2"); + writeRegionPoints(of); + vector<RevEngPoint*> bd_pts = extractBdPoints(); + of << "400 1 0 4 0 0 0 255" << std::endl; + of << bd_pts.size() << std::endl; + for (size_t kj=0; kj<bd_pts.size(); ++kj) + of << bd_pts[kj]->getPoint() << std::endl; +#endif + // Principal curvature summary + updateInfo(); +} + +//=========================================================================== +BoundingBox RevEngRegion::getParameterBox() +//=========================================================================== +{ + BoundingBox parbox(2); + if (associated_sf_.size() == 0) + return parbox; // No surface means that the points are not parameterized + + for (size_t ki=0; ki<group_points_.size(); ++ki) + { + Vector2D par = group_points_[ki]->getPar(); + Point par2(par[0], par[1]); + parbox.addUnionWith(par2); + } + return parbox; +} + + +//=========================================================================== +RevEngPoint* RevEngRegion::seedPointPlane(int min_next, double rfac, double angtol) +//=========================================================================== +{ + double min_in = 0; + int min_ix = -1; + int multfac = 10; + for (size_t ki=0; ki<group_points_.size(); ++ki) + { + double local_len = group_points_[ki]->getMeanEdgLen(); + Point normal = group_points_[ki]->getLocFuncNormal(); + double radius = 2.0*rfac*local_len; + vector<RevEngPoint*> nearpts; + group_points_[ki]->fetchClosePoints2(radius, min_next, 5*min_next, + nearpts, this); + + // Count deviant points + int deviant = 0; + for (size_t kj=0; kj<nearpts.size(); ++kj) + { + Point curr_norm = nearpts[kj]->getLocFuncNormal(); + double ang = curr_norm.angle(normal); + if (nearpts[kj]->region() != this || ang > angtol) + ++deviant; + } + + if (deviant == 0) + return group_points_[ki]; // Seed point found + + if ((int)nearpts.size() - deviant > min_in) + { + min_in = (int)nearpts.size() - deviant; + min_ix = (int)ki; + if (min_in < multfac*min_next) + break; + } + } + return (min_ix >= 0) ? group_points_[min_ix] : 0; +} + +//=========================================================================== +void RevEngRegion::growLocalPlane(Point mainaxis[3], + double tol, vector<RevEngPoint*>& plane_pts, + shared_ptr<Plane>& plane_out) +//=========================================================================== +{ + // Get seed point for local grow + int min_next = std::max(10, (int)group_points_.size()/100); + double rfac = 3; + double angtol = 0.1; + RevEngPoint* seed = seedPointPlane(min_next, rfac, angtol); + if (!seed) + return; + +#ifdef DEBUG_SEGMENT + std::ofstream of("seed.g2"); + of << "400 1 0 4 200 0 55 255" << std::endl; + of << "1" << std::endl; + of << seed->getPoint() << std::endl; +#endif + // Fetch nearby points belonging to the same region + double local_len = seed->getMeanEdgLen(); + double radius = 2.0*rfac*local_len; + vector<RevEngPoint*> nearpts; + seed->fetchClosePoints2(radius, min_next, 5*min_next, nearpts, this); + nearpts.insert(nearpts.begin(), seed); + if ((int)nearpts.size() < min_next/2) + return; + + // Approximate with plane + shared_ptr<Plane> plane = computePlane(nearpts, avnorm_, mainaxis); + + double eps = 1.0e-6; + double maxdist, avdist; + int num_inside, num2_inside; + vector<pair<double, double> > dist_ang; + vector<double> parvals; + vector<RevEngPoint*> inpt, outpt; + RevEngUtils::distToSurf(nearpts.begin(), nearpts.end(), + plane, tol, maxdist, avdist, num_inside, num2_inside, + inpt, outpt, parvals, dist_ang, angtol); + + if (maxdist > tol) + return; // For the time being + + + for (size_t ki=0; ki<nearpts.size(); ++ki) + nearpts[ki]->setVisited(); + size_t prev_size = nearpts.size(); + while (true) + { + for (size_t ki=0; ki<nearpts.size(); ++ki) + { + vector<ftSamplePoint*> next = nearpts[ki]->getNeighbours(); + for (size_t kj=0; kj<next.size(); ++kj) + { + RevEngPoint *pt = dynamic_cast<RevEngPoint*>(next[kj]); + if ((!pt->hasRegion()) || pt->region() != this) + continue; + if (pt->visited()) + continue; + Vector3D xyz = pt->getPoint(); + + double upar, vpar, dist; + Point close; + plane->closestPoint(Point(xyz[0],xyz[1],xyz[2]), upar, vpar, close, dist, eps); + pt->setVisited(); + if (dist < tol) + nearpts.push_back(pt); + } + } + + for (size_t ki=0; ki<group_points_.size(); ++ki) + { + if (std::find(nearpts.begin(), nearpts.end(), group_points_[ki]) == nearpts.end()) + group_points_[ki]->unsetVisited(); + } + + if (nearpts.size() == prev_size) + break; + + shared_ptr<Plane> plane2 = computePlane(nearpts, avnorm_, mainaxis); + + double maxdist2, avdist2; + int num_inside2, num2_inside2; + vector<pair<double, double> > dist_ang2; + vector<double> parvals2; + RevEngUtils::distToSurf(nearpts.begin(), nearpts.end(), + plane2, tol, maxdist2, avdist2, num_inside2, + num2_inside2, inpt, + outpt, parvals2, dist_ang2, angtol); + if (maxdist2 > tol) + break; + + prev_size = nearpts.size(); + plane = plane2; + maxdist = maxdist2; + avdist = avdist2; + num_inside = num_inside2; + parvals = parvals2; + dist_ang = dist_ang2; + } + + for (size_t ki=0; ki<group_points_.size(); ++ki) + group_points_[ki]->unsetVisited(); +#ifdef DEBUG_EXTRACT + std::ofstream of2("plane_pts.g2"); + of2 << "400 1 0 4 100 155 0 255" << std::endl; + of2 << nearpts.size() << std::endl; + for (size_t ki=0; ki<nearpts.size(); ++ki) + of2 << nearpts[ki]->getPoint() << std::endl; + + plane->writeStandardHeader(of2); + plane->write(of2); +#endif + plane_pts = nearpts; + plane_out = plane; + + int stop_break = 1; + +} + +//=========================================================================== +void RevEngRegion::segmentByPlaneGrow(Point mainaxis[3], double tol, + double angtol, int min_pt, + vector<shared_ptr<HedgeSurface> >& hedgesfs, + vector<HedgeSurface*>& prevsfs, + vector<vector<RevEngPoint*> >& out_groups) +//=========================================================================== +{ + // Extract group of planar points and associated plane + int min_nmb_pts = std::max((int)group_points_.size()/100, 10); + vector<RevEngPoint*> plane_pts; + shared_ptr<Plane> plane; + growLocalPlane(mainaxis, tol, plane_pts, plane); + if ((int)plane_pts.size() < min_nmb_pts || plane_pts.size() == group_points_.size()) + return; + + // Fetch accuracy information + double maxd, avd; + int num_in, num2_in; + vector<pair<double, double> > dist_ang; + vector<double> parvals; + vector<RevEngPoint*> inpt, outpt; + RevEngUtils::distToSurf(plane_pts.begin(), plane_pts.end(), + plane, tol, maxd, avd, num_in, num2_in, inpt, + outpt, parvals, dist_ang, angtol); + + // Extract remaining points + for (size_t ki=0; ki<plane_pts.size(); ++ki) + plane_pts[ki]->setVisited(); + + vector<RevEngPoint*> remaining_pts; + for (size_t ki=0; ki<group_points_.size(); ++ki) + { + if (!group_points_[ki]->visited()) + { + remaining_pts.push_back(group_points_[ki]); + removePoint(group_points_[ki]); + } + } + + for (size_t ki=0; ki<plane_pts.size(); ++ki) + plane_pts[ki]->unsetVisited(); + + if (hasSurface()) + { + // No longer valid + prevsfs.insert(prevsfs.end(), associated_sf_.begin(), associated_sf_.end()); + clearSurface(); + } + + if ((int)plane_pts.size() >= min_pt) + { + // Register current plane + int sf_flag = defineSfFlag(0, tol, num_in, num2_in, + avd, false); + for (size_t ki=0; ki<plane_pts.size(); ++ki) + { + plane_pts[ki]->setPar(Vector2D(parvals[2*ki],parvals[2*ki+1])); + plane_pts[ki]->setSurfaceDist(dist_ang[ki].first, dist_ang[ki].second); + } + setAccuracy(maxd, avd, num_in, num2_in); + shared_ptr<HedgeSurface> hedge(new HedgeSurface(plane, this)); + setHedge(hedge.get()); + hedgesfs.push_back(hedge); + setSurfaceFlag(sf_flag); + } + + // Store as base surface and primary surface + setBaseSf(plane, maxd, avd, num_in, num2_in); + + updateInfo(tol, angtol); + + // Distribute remaining points into groups and create regions + shared_ptr<RevEngRegion> reg(new RevEngRegion(classification_type_, + edge_class_type_, + remaining_pts)); + vector<vector<RevEngPoint*> > connected; + reg->splitRegion(connected); + out_groups.push_back(reg->getPoints()); + if (connected.size() > 0) + out_groups.insert(out_groups.end(), connected.begin(), connected.end()); +} + + + +//=========================================================================== +bool RevEngRegion::extractPlane(Point mainaxis[3], + double tol, int min_pt, int min_pt_reg, + double angtol, int prefer_elementary, + vector<shared_ptr<HedgeSurface> >& hedgesfs, + vector<HedgeSurface*>& prevsfs, + vector<vector<RevEngPoint*> >& out_groups) +//=========================================================================== +{ + // std::ofstream of("curr_region.g2"); + // writeRegionInfo(of); + + // std::ofstream of2("curr_normals.g2"); + // writeUnitSphereInfo(of2); + +#ifdef DEBUG + if (normalcone_.greaterThanPi()) + { + std::cout << "Greater than pi" << std::endl; + std::ofstream ofpi("pi_region.g2"); + writeRegionInfo(ofpi); + } +#endif + + bool found = false; + int min_nmb = 20; + if ((int)group_points_.size() < min_nmb) + return false; + + // vector<RevEngPoint*> in, out; + // analysePlaneProperties(normal, angtol, in, out); + + // shared_ptr<Plane> surf1(new Plane(pos, normal1)); + // shared_ptr<Plane> surf(new Plane(pos, normal)); + + // Point pos2 = pos; + // Point normal2; + // vector<pair<vector<RevEngPoint*>::iterator, + // vector<RevEngPoint*>::iterator> > group; + // group.push_back(std::make_pair(group_points_.begin(), group_points_.end())); + // RevEngUtils::computePlane(group, pos2, normal2); + // shared_ptr<Plane> surf2(new Plane(pos2, normal2)); + + // vector<RevEngPoint*> in3, out3; + // analysePlaneProperties(normal3, angtol, in3, out3); + + vector<pair<shared_ptr<ElementarySurface>, RevEngRegion*> > adj_elem, adj_elem_base; + getAdjacentElemInfo(adj_elem, adj_elem_base); + + shared_ptr<Plane> surf3 = computePlane(group_points_, avnorm_, mainaxis); //(new Plane(pos3, normal3)); + + // Check accuracy + // double maxdist, avdist; + // double maxdist1, avdist1; + // double maxdist2, avdist2; + double maxdist3, avdist3; + int num_inside3, num2_inside3; //, num_inside1, num_inside2, num_inside3; + vector<RevEngPoint*> inpt, outpt; + // RevEngUtils::distToSurf(group_points_.begin(), group_points_.end(), + // surf, tol, maxdist, avdist, num_inside); + // RevEngUtils::distToSurf(group_points_.begin(), group_points_.end(), + // surf1, tol, maxdist1, avdist1, num_inside1); + // RevEngUtils::distToSurf(group_points_.begin(), group_points_.end(), + // surf2, tol, maxdist2, avdist2, num_inside2); + vector<pair<double, double> > dist_ang; + vector<double> parvals; + RevEngUtils::distToSurf(group_points_.begin(), group_points_.end(), + surf3, tol, maxdist3, avdist3, num_inside3, num2_inside3, + inpt, outpt, parvals, dist_ang, angtol); +#ifdef DEBUG_EXTRACT + std::ofstream ofd("in_out_plane.g2"); + ofd << "400 1 0 4 155 50 50 255" << std::endl; + ofd << inpt.size() << std::endl; + for (size_t kr=0; kr<inpt.size(); ++kr) + ofd << inpt[kr]->getPoint() << std::endl; + ofd << "400 1 0 4 50 155 50 255" << std::endl; + ofd << outpt.size() << std::endl; + for (size_t kr=0; kr<outpt.size(); ++kr) + ofd << outpt[kr]->getPoint() << std::endl; +#endif + + if (inpt.size() > group_points_.size()/3 && (int)inpt.size() > min_nmb && + (normalcone_.angle() > angtol || + normalcone_.centre().angle(surf3->getNormal()) > angtol) && + (!(basesf_.get() && basesf_->instanceType() == Class_Cylinder))) + { + vector<RevEngPoint*> ang_points; + double dtol = std::min(0.5*tol, 1.5*avdist3); + identifyAngPoints(dist_ang, angtol, dtol, ang_points); + if (ang_points.size() < group_points_.size()/2) + { + extractSpesPoints(ang_points, out_groups, true); + + if (out_groups.size() > 0) + { + // Ensure connected region + vector<vector<RevEngPoint*> > separate_groups; + splitRegion(separate_groups); + if (separate_groups.size() > 0) + { + out_groups.insert(out_groups.end(), separate_groups.begin(), + separate_groups.end()); + } + + shared_ptr<Plane> plane_in = + computePlane(group_points_, avnorm_, mainaxis); + vector<RevEngPoint*> inpt_in, outpt_in; //, inpt2, outpt2; + vector<pair<double, double> > dist_ang_in; + vector<double> parvals_in; + double maxd_in, avd_in; + int num2_in, num2_in2; + RevEngUtils::distToSurf(group_points_.begin(), group_points_.end(), + plane_in, tol, maxd_in, avd_in, num2_in, num2_in2, + inpt_in, outpt_in, parvals_in, dist_ang_in, angtol); +#ifdef DEBUG_EXTRACT + std::ofstream ofd2("in_out_plane2.g2"); + ofd2 << "400 1 0 4 155 50 50 255" << std::endl; + ofd2 << inpt_in.size() << std::endl; + for (size_t kr=0; kr<inpt_in.size(); ++kr) + ofd2 << inpt_in[kr]->getPoint() << std::endl; + ofd2 << "400 1 0 4 50 155 50 255" << std::endl; + ofd2 << outpt_in.size() << std::endl; + for (size_t kr=0; kr<outpt_in.size(); ++kr) + ofd2 << outpt_in[kr]->getPoint() << std::endl; +#endif + // if (num2_in > num_inside3 || avd_in < avdist3) + // { + std::swap(surf3, plane_in); + std::swap(num_inside3, num2_in); + std::swap(num2_inside3, num2_in2); + std::swap(avdist3, avd_in); + std::swap(maxdist3, maxd_in); + std::swap(parvals, parvals_in); + std::swap(dist_ang, dist_ang_in); + // std::cout << "Plane swap" << std::endl; + // std::cout << group_points_.size() << " " << num2_in << " "; + // std::cout<< num_inside3 << " " << avd_in << " " << avdist3; + // std::cout << " " << maxd_in << " " << maxdist3 << std::endl; + // } + } + } + } + + Point low = bbox_.low(); + Point high = bbox_.high(); + //double len = low.dist(high); + //surf3->setParameterBounds(-len, -len, len, len); +#ifdef DEBUG_EXTRACT + std::ofstream plane("curr_plane.g2"); + surf3->writeStandardHeader(plane); + surf3->write(plane); +#endif + //int num = (int)group_points_.size(); + int sf_flag = defineSfFlag(0, tol, num_inside3, num2_inside3, + avdist3, false); + if (sf_flag < ACCURACY_POOR) + { + found = true; + for (size_t kh=0; kh<group_points_.size(); ++kh) + { + group_points_[kh]->setPar(Vector2D(parvals[2*kh],parvals[2*kh+1])); + group_points_[kh]->setSurfaceDist(dist_ang[kh].first, dist_ang[kh].second); + } + setAccuracy(maxdist3, avdist3, num_inside3, num2_inside3); + +#ifdef DEBUG + std::cout << "Plane. N1: " << num << ", N2: " << num_inside3 << ", max: " << maxdist3 << ", av: " << avdist3 << std::endl; +#endif + + shared_ptr<HedgeSurface> hedge(new HedgeSurface(surf3, this)); + for (size_t kh=0; kh<associated_sf_.size(); ++kh) + prevsfs.push_back(associated_sf_[kh]); + setHedge(hedge.get()); + hedgesfs.push_back(hedge); + setSurfaceFlag(sf_flag); + } + if (!basesf_.get() || + (num_inside3 >= num_in_base_ && avdist3 < avdist_base_)) + setBaseSf(surf3, maxdist3, avdist3, num_inside3, num2_inside3); + + return found; +} + + +//=========================================================================== +shared_ptr<Plane> RevEngRegion::computePlane(vector<RevEngPoint*>& points, + const Point& norm_dir, Point mainaxis[3]) +//=========================================================================== +{ + Point normal1 = normalcone_.centre(); + Point normal(0.0, 0.0, 0.0); + Point pos(0.0, 0.0, 0.0); + double wgt = 1.0/(double)(points.size()); + for (size_t ki=0; ki<points.size(); ++ki) + { + Point curr = points[ki]->getLocFuncNormal(); + Vector3D xyz = points[ki]->getPoint(); + normal += wgt*curr; + pos += wgt*Point(xyz[0], xyz[1], xyz[2]); + } + + ImplicitApprox impl; + impl.approx(points, 1); + Point pos3, normal3; + bool found = impl.projectPoint(pos, normal, pos3, normal3); + if (!found) + { + pos3 = pos; + normal3 = normal; + normal3.normalize(); + } + if (normal3*norm_dir < 0.0) + normal3 *= -1.0; + + // Define x-axis + int ix = -1; + double minang = M_PI; + for (int ka=0; ka<3; ++ka) + { + double ang = mainaxis[ka].angle(normal3); + ang = std::min(ang, M_PI-ang); + if (ang < minang) + { + minang = ang; + ix = ka; + } + } + + Point Cy = mainaxis[(ix+1)%3].cross(normal3); + Point Cx = normal3.cross(Cy); + + shared_ptr<Plane> surf(new Plane(pos3, normal3, Cx)); + Point low = bbox_.low(); + Point high = bbox_.high(); + //double len = low.dist(high); + //surf->setParameterBounds(-len, -len, len, len); + + bool plane_project = false; + if (plane_project) + { + vector<pair<vector<RevEngPoint*>::iterator, + vector<RevEngPoint*>::iterator> > group; + group.push_back(std::make_pair(points.begin(), points.end())); + Point vec1, vec2; + surf->getSpanningVectors(vec1, vec2); + vector<Point> projected1, projected2; + double maxdp1, avdp1, maxdp2, avdp2; + RevEngUtils::projectToPlane(group, vec1, pos3, projected1, maxdp1, avdp1); + RevEngUtils::projectToPlane(group, vec2, pos3, projected2, maxdp2, avdp2); + +#ifdef DEBUG_EXTRACT + std::ofstream ofp3("plane_project.g2"); + ofp3 << "400 1 0 4 255 0 0 255" << std::endl; + ofp3 << projected1.size() << std::endl; + for (size_t kr=0; kr<projected1.size(); ++kr) + ofp3 << projected1[kr] << std::endl; + ofp3 << "400 1 0 4 255 0 0 255" << std::endl; + ofp3 << projected2.size() << std::endl; + for (size_t kr=0; kr<projected2.size(); ++kr) + ofp3 << projected2[kr] << std::endl; +#endif + } + return surf; +} + +//=========================================================================== +void RevEngRegion::getDistAndAng(vector<pair<double,double> >& distang) +//=========================================================================== +{ + distang.resize(group_points_.size()); + for (size_t ki=0; ki<group_points_.size(); ++ki) + { + double dist, ang; + group_points_[ki]->getSurfaceDist(dist, ang); + distang[ki] = std::make_pair(dist, ang); + } +} + +//=========================================================================== +bool RevEngRegion::possiblePlane(double angtol, double inlim) +//=========================================================================== +{ + if (planartype()) + return true; + + double wgt = 1.0/(double)group_points_.size(); + Point avnorm(0.0, 0.0, 0.0); + for (size_t ki=0; ki<group_points_.size(); ++ki) + { + Point curr = group_points_[ki]->getLocFuncNormal(); + avnorm += wgt*curr; + } + + int nmb_in = 0; + for (size_t ki=0; ki<group_points_.size(); ++ki) + { + Point curr = group_points_[ki]->getLocFuncNormal(); + double ang = curr.angle(avnorm); + if (ang <= angtol) + ++nmb_in; + } + + double frac = (double)nmb_in/(double)group_points_.size(); + return (frac >= inlim); +} + +//=========================================================================== +vector<RevEngRegion*> RevEngRegion::fetchAdjacentPlanar() +//=========================================================================== +{ + vector<RevEngRegion*> adjacent_planar; + for (auto it=adjacent_regions_.begin(); it!=adjacent_regions_.end(); ++it) + { + if ((*it)->hasSurface()) + { + shared_ptr<ParamSurface> sf = (*it)->getSurface(0)->surface(); + if (sf->instanceType() == Class_Plane) + adjacent_planar.push_back(*it); + } + } + + return adjacent_planar; +} + +//=========================================================================== +vector<RevEngRegion*> RevEngRegion::fetchAdjacentCylindrical() +//=========================================================================== +{ + vector<RevEngRegion*> adjacent_cylindrical; + for (auto it=adjacent_regions_.begin(); it!=adjacent_regions_.end(); ++it) + { + if ((*it)->hasSurface()) + { + shared_ptr<ParamSurface> sf = (*it)->getSurface(0)->surface(); + if (sf->instanceType() == Class_Cylinder) + adjacent_cylindrical.push_back(*it); + } + } + + return adjacent_cylindrical; +} + +//=========================================================================== +Point RevEngRegion::directionFromAdjacent(double angtol) +//=========================================================================== +{ + Point dir; + vector<std::pair<Point,int> > all_dir; + for (auto it=adjacent_regions_.begin(); it!=adjacent_regions_.end(); ++it) + { + if ((*it)->hasSurface()) + { + shared_ptr<ParamSurface> sf = (*it)->getSurface(0)->surface(); + if (sf->instanceType() == Class_Plane || sf->instanceType() == Class_Cylinder) + { + shared_ptr<ElementarySurface> elem = + dynamic_pointer_cast<ElementarySurface,ParamSurface>(sf); + Point curr_dir = elem->direction(); + size_t kj; + for (kj=0; kj<all_dir.size(); ++kj) + { + double ang = curr_dir.angle(all_dir[kj].first); + if (M_PI-ang < ang) + { + curr_dir *= -1.0; + ang = M_PI - ang; + } + if (ang < angtol) + { + int num = (*it)->numPoints(); + double fac = 1.0/(double)(all_dir[kj].second+num); + curr_dir = fac*(all_dir[kj].second*all_dir[kj].first + num*curr_dir); + break; + } + } + if (kj == all_dir.size()) + all_dir.push_back(std::make_pair(curr_dir, (*it)->numPoints())); + } + } + } + + for (size_t ki=0; ki<all_dir.size(); ++ki) + for (size_t kj=ki+1; kj<all_dir.size(); ++kj) + if (all_dir[kj].second > all_dir[ki].second) + std::swap(all_dir[ki], all_dir[kj]); + + if (all_dir.size() > 0) + dir = all_dir[0].first; + + return dir; +} + +//=========================================================================== +bool RevEngRegion::potentialBlend(double angtol) +//=========================================================================== +{ + double pihalf = 0.5*M_PI; + vector<pair<shared_ptr<ElementarySurface>, RevEngRegion*> > adj_elem, adj_elem_base; + getAdjacentElemInfo(adj_elem, adj_elem_base); + for (size_t ki=0; ki<adj_elem.size(); ++ki) + { + ClassType type1 = adj_elem[ki].first->instanceType(); + Point dir1 = adj_elem[ki].first->direction(); + if (type1 != Class_Plane && type1 != Class_Cylinder) + continue; + for (size_t kj=ki+1; kj<adj_elem.size(); ++kj) + { + ClassType type2 = adj_elem[kj].first->instanceType(); + if (type2 != Class_Plane && type2 != Class_Cylinder) + continue; + if (type1 == Class_Cylinder && type2 == Class_Cylinder) + continue; + Point dir2 = adj_elem[kj].first->direction(); + double ang = dir1.angle(dir2); + if (type1 == Class_Plane && type2 == Class_Plane) + ang = std::min(ang, M_PI-ang); + else + ang = fabs(pihalf - ang); + if (ang > angtol) + return true; + } + } + return false; +} + +//=========================================================================== +void RevEngRegion::neighbourBlends(vector<shared_ptr<CurveOnSurface> >& cvs, + double width, double tol, + vector<RevEngRegion*>& new_blends) +//=========================================================================== +{ + for (auto it=adjacent_regions_.begin(); it!=adjacent_regions_.end(); ++it) + { + if ((*it)->hasAssociatedBlend()) + continue; + if ((*it)->hasRevEdges()) + continue; + int in_blend = 0; + if ((*it)->isInBlend(cvs, width, tol, in_blend)) + new_blends.push_back(*it); + } +} + +//=========================================================================== +bool RevEngRegion::isInBlend(vector<shared_ptr<CurveOnSurface> >& cvs, + double width, double tol, int& in_blend) +//=========================================================================== +{ + double lim = 0.9; + in_blend = 0; + double tmin = cvs[0]->startparam(); + double tmax = cvs[cvs.size()-1]->endparam(); + for (size_t ki=0; ki<group_points_.size(); ++ki) + { + double tpar, dist=std::numeric_limits<double>::max();; + Vector3D xyz = group_points_[ki]->getPoint(); + Point pt(xyz[0], xyz[1], xyz[2]); + Point close; + for (size_t kj=0; kj<cvs.size(); ++kj) + { + cvs[kj]->closestPoint(pt, cvs[kj]->startparam(), cvs[kj]->endparam(), + tpar, close, dist); + if (tpar > tmin && tpar < tmax && dist < width+tol) + in_blend++; + } + } + if ((double)in_blend >= lim*(double)group_points_.size()) + return true; + else + return false; +} + +//=========================================================================== +void RevEngRegion::getAdjacentElemInfo(vector<pair<shared_ptr<ElementarySurface>, RevEngRegion*> >& adj_elem, + vector<pair<shared_ptr<ElementarySurface>, RevEngRegion*> >& adj_elem_base) +//=========================================================================== +{ + for (auto it=adjacent_regions_.begin(); it!=adjacent_regions_.end(); ++it) + { + bool found = false; + if ((*it)->hasSurface()) + { + shared_ptr<ParamSurface> sf = (*it)->getSurface(0)->surface(); + shared_ptr<ElementarySurface> elem = + dynamic_pointer_cast<ElementarySurface,ParamSurface>(sf); + if (elem.get()) + { + adj_elem.push_back(std::make_pair(elem,*it)); + found = true; + } + } + + if ((*it)->hasBaseSf() && (!found)) + { + shared_ptr<ParamSurface> sf = (*it)->getBase(); + shared_ptr<ElementarySurface> elem = + dynamic_pointer_cast<ElementarySurface,ParamSurface>(sf); + if (elem.get()) + { + adj_elem_base.push_back(std::make_pair(elem, *it)); + found = true; + } + } + + } + +#ifdef DEBUG_ADJACENT + std::ofstream of("adj_sf_pts.g2"); + for (size_t ki=0; ki<adj_elem.size(); ++ki) + adj_elem[ki].second->writeRegionPoints(of); +#endif +} + +//=========================================================================== +bool RevEngRegion::possibleCylinder(double angtol, double inlim) +//=========================================================================== +{ + // if (cylindertype()) + // return true; + + double wgt = 1.0/(double)group_points_.size(); + Point avvec = wgt*group_points_[0]->minCurvatureVec(); + for (size_t ki=1; ki<group_points_.size(); ++ki) + { + Point curr = group_points_[ki]->minCurvatureVec(); + if (curr*avvec < 0.0) + curr *= -1; + avvec += wgt*curr; + } + + int nmb_in = 0; + for (size_t ki=0; ki<group_points_.size(); ++ki) + { + Point curr = group_points_[ki]->minCurvatureVec(); + double ang = curr.angle(avvec); + ang = std::min(ang, M_PI-ang); + if (ang <= angtol) + ++nmb_in; + } + + double frac = (double)nmb_in/(double)group_points_.size(); + return (frac >= inlim); +} + +//=========================================================================== +bool RevEngRegion::possibleCone(double tol, double inlim) +//=========================================================================== +{ + return true; // For the time being +} + +//=========================================================================== +bool RevEngRegion::possibleTorus(double tol, double inlim) +//=========================================================================== +{ + // if (planartype() || cylindertype()) + // return false; + // Compute curvature variations + double k1mean = 0.0, k2mean = 0.0; + double k1_1 = 0.0, k1_2 = 0.0, k2_1 = 0.0, k2_2 = 0.0; + double d1 = 0.0, d2 = 0.0; + double wgt = 1.0/(double)group_points_.size(); + Point vec(0.0, 0.0, 0.0); + + double eps = 1.0e-3; + vector<Vector3D> cneg, cpos, czero; + double k1min = std::numeric_limits<double>::max(); + double k1max = std::numeric_limits<double>::lowest(); + double k2min = std::numeric_limits<double>::max(); + double k2max = std::numeric_limits<double>::lowest(); + int k1pos = 0, k1neg = 0, k2pos = 0, k2neg = 0; + for (size_t kr=0; kr<group_points_.size(); ++kr) + { + double kmin = group_points_[kr]->minPrincipalCurvature(); + double kmax = group_points_[kr]->maxPrincipalCurvature(); + d1 += kmin; + d2 += kmax; + k1_1 += kmin*kmin; + k2_1 += kmax*kmax; + k1_2 += fabs(kmin); + k2_2 += fabs(kmax); + k1mean += wgt*kmin; + k2mean += wgt*kmax; + k1min = std::min(k1min, kmin); + k1max = std::max(k1max, kmin); + k2min = std::min(k2min, kmax); + k2max = std::max(k2max, kmax); + if (kmin < 0.0) + k1neg++; + else + k1pos++; + if (kmax < 0.0) + k2neg++; + else + k2pos++; + + Point norm = group_points_[kr]->getLocFuncNormal(); + Point minvec = group_points_[kr]->minCurvatureVec(); + Point temp = norm.cross(minvec); + temp.normalize_checked(); + vec += wgt*temp; + if (group_points_[kr]->GaussCurvature()*group_points_[kr]->meanCurvature() < -eps) + cneg.push_back(group_points_[kr]->getPoint()); + else if (group_points_[kr]->GaussCurvature()*group_points_[kr]->meanCurvature() > eps) + cpos.push_back(group_points_[kr]->getPoint()); + else + czero.push_back(group_points_[kr]->getPoint()); + } + //double vark1 = ((double)group_points_.size()*k1_1)/fabs(d1) - fabs(k1_2); + //double vark2 = ((double)group_points_.size()*k2_1)/fabs(d2) - fabs(k2_2); + + double klim1 = 0.1*fabs(k1mean); + double klim2 = 0.1*fabs(k2mean); + int nmb1=0, nmb2=0; + for (size_t kr=0; kr<group_points_.size(); ++kr) + { + double kmin = group_points_[kr]->minPrincipalCurvature(); + double kmax = group_points_[kr]->maxPrincipalCurvature(); + if (fabs(kmin - k1mean) < klim1) + ++nmb1; + if (fabs(kmax - k2mean) < klim2) + ++nmb2; + } + + //double frac1 = (double)nmb1/(double)group_points_.size(); + //double frac2 = (double)nmb2/(double)group_points_.size(); + +#ifdef DEBUG_EXTRACT + std::ofstream of("posnegcurv.g2"); + of << "400 1 0 4 0 100 155 255" << std::endl; + of << cneg.size() << std::endl; + for (size_t kr=0; kr<cneg.size(); ++kr) + of << cneg[kr] << std::endl; + of << "400 1 0 4 0 255 0 255" << std::endl; + of << cpos.size() << std::endl; + for (size_t kr=0; kr<cpos.size(); ++kr) + of << cpos[kr] << std::endl; + of << "400 1 0 4 200 55 0 255" << std::endl; + of << czero.size() << std::endl; + for (size_t kr=0; kr<czero.size(); ++kr) + of << czero[kr] << std::endl; +#endif + // Something with variation in curvature + return true; // For the time being +} + +//=========================================================================== +void RevEngRegion::analysePlaneProperties(Point avnorm, double angtol, + vector<RevEngPoint*>& in, + vector<RevEngPoint*> out) +//=========================================================================== +{ + vector<double> midang(group_points_.size()); + for (size_t ki=0; ki<group_points_.size(); ++ki) + { + Point curr = group_points_[ki]->getLocFuncNormal(); + double ang = curr.angle(avnorm); + midang[ki] = ang; + if (ang <= angtol) + in.push_back(group_points_[ki]); + else + out.push_back(group_points_[ki]); + } + + std::sort(midang.begin(), midang.end()); + int stop_break = 1; +} + +//=========================================================================== +void RevEngRegion::analyseNormals(double tol, Point& normal, Point& centre, + double& radius) //double& beta) +//=========================================================================== +{ +#ifdef DEBUG0 + std::ofstream of2("curr_normals.g2"); + of2 << "400 1 0 4 100 0 155 255" << std::endl; + of2 << group_points_.size() << std::endl; + for (size_t kr=0; kr<group_points_.size(); ++kr) + { + RevEngPoint *pt = dynamic_cast<RevEngPoint*>(group_points_[kr]); + Point norm = pt->getLocFuncNormal(); + of2 << norm << std::endl; + } + Sphere sph(1.0, Point(0.0, 0.0, 0.0), Point(0.0, 0.0, 1.0), + Point(1.0, 0.0, 0.0)); + sph.writeStandardHeader(of2); + sph.write(of2); +#endif + + Point axis; + Point Cx; + Point Cy; + vector<pair<vector<RevEngPoint*>::iterator, + vector<RevEngPoint*>::iterator> > group; + group.push_back(std::make_pair(group_points_.begin(), group_points_.end())); + RevEngUtils::computeAxis(group, axis, Cx, Cy); + + Point pnt(0.0, 0.0, 0.0); + Point pos(0.0, 0.0, 0.0); + vector<Point> vec(group_points_.size()); + double wgt = 1.0/(double)(group_points_.size()); + for (size_t ki=0; ki<group_points_.size(); ++ki) + { + Vector3D xyz = group_points_[ki]->getPoint(); + pos += wgt*Point(xyz[0], xyz[1], xyz[2]); + vec[ki] = group_points_[ki]->getLocFuncNormal(); + pnt += wgt*vec[ki]; + } + Point tmpnorm; + double maxang = 0.0; + size_t ix = 0; + for (size_t kj=1; kj<vec.size(); ++kj) + { + double ang = vec[0].angle(vec[kj]); + ang = std::min(ang, M_PI-ang); + if (ang > maxang) + { + maxang = ang; + ix = kj; + } + } + tmpnorm = vec[0].cross(vec[ix]); + tmpnorm.normalize(); + + ImplicitApprox impl; + impl.approxPoints(vec, 1); + + //Point pos; //, normal; + bool found = impl.projectPoint(pos, tmpnorm, pnt, normal); + if (!found) + { + pnt = pos; + normal = tmpnorm; + } + shared_ptr<Plane> surf(new Plane(pnt, axis)); + +#ifdef DEBUG0 + Point origo(0.0, 0.0,0.0); + of2 << "410 1 0 4 255 0 0 255" << std::endl; + of2 << "1" << std::endl; + of2 << origo << " " << axis << std::endl; +#endif + + double maxdist, avdist; + int num_inside; + //int num = (int)vec.size(); + vector<double> distance; + RevEngUtils::distToSurf(vec, surf, tol, maxdist, avdist, num_inside, + distance); + + //double radius; + RevEngUtils::computeRadius(vec, axis, Cx, Cy, radius); + centre = pnt; + // double r2 = std::min(radius, 1.0); + // double phi = acos(r2); + // double delta = r2*tan(phi); + // double alpha = (delta > 1.0e-10) ? atan((1.0-r2)/delta) : M_PI; + // beta = M_PI - alpha; + int stop_break = 1; + +} + +//=========================================================================== +bool RevEngRegion::feasiblePlane(double zero_H, double zero_K) const +//=========================================================================== +{ + double angtol = 0.2; + double in_lim = 0.8; + double in_lim2 = 0.5; + double fac = 5.0; + if (basesf_ && basesf_->instanceType() == Class_Plane) + return true; + + if (normalcone_.angle() < angtol && (!normalcone_.greaterThanPi())) + return true; + + int nmb_in = 0; + for (size_t kr=0; kr<group_points_.size(); ++kr) + { + Point normal1 = group_points_[kr]->getLocFuncNormal(); + Point normal2 = group_points_[kr]->getTriangNormal(); + if (avnorm_.angle(normal1) <= angtol || + avnorm2_.angle(normal2) <= angtol) + nmb_in++; + } + double in_frac = (double)nmb_in/(double)group_points_.size(); + if (in_frac > in_lim) + return true; + + if (in_frac < in_lim2) + return false; + + if (std::max(MAH_, MAK_) > fac*std::max(zero_H, zero_K)) + return false; + + return true; +} + +//=========================================================================== +bool RevEngRegion::feasibleCylinder(double zero_H, double zero_K) const +//=========================================================================== +{ + double fac1 = 5.0; + double fac2 = 0.5; + if (basesf_ && basesf_->instanceType() == Class_Cylinder) + return true; + if (MAK_ > fac1*zero_H) + return false; + if (MAK_ > fac2*MAH_) + return false; + // if (fabs(avK_) < fac2*MAK_) + // return false; + + return true; +} + + +//=========================================================================== +bool RevEngRegion::extractCylinder(double tol, int min_pt, int min_pt_reg, + double angtol, int prefer_elementary, + vector<shared_ptr<HedgeSurface> >& hedgesfs, + vector<HedgeSurface*>& prevsfs, + vector<vector<RevEngPoint*> >& out_groups, + bool& repeat) +//=========================================================================== +{ + bool found = false; + int min_nmb = 20; + //double eps = 1.0e-6; + if ((int)group_points_.size() < min_nmb) + return false; + + vector<pair<shared_ptr<ElementarySurface>, RevEngRegion*> > adj_elem, adj_elem_base; + getAdjacentElemInfo(adj_elem, adj_elem_base); + + vector<vector<RevEngPoint*> > configs; + shared_ptr<Cone> cone; + shared_ptr<Cylinder> cyl = computeCylinder(group_points_, tol); +#ifdef DEBUG_CYL + std::ofstream ofs("cyl.g2"); + shared_ptr<Cylinder> cyl2(cyl->clone()); + double diag = bbox_.low().dist(bbox_.high()); + cyl2->setParamBoundsV(-0.5*diag,0.5*diag); + cyl2->writeStandardHeader(ofs); + cyl2->write(ofs); +#endif + + // Check accuracy + double maxd, avd; + int num2, num2_2; + vector<RevEngPoint*> inpt, outpt; + vector<pair<double, double> > dist_ang; + vector<double> parvals; + RevEngUtils::distToSurf(group_points_.begin(), group_points_.end(), + cyl, tol, maxd, avd, num2, num2_2, inpt, outpt, + parvals, dist_ang, angtol); + +#ifdef DEBUG_CYL + std::ofstream ofd("in_out_cyl.g2"); + ofd << "400 1 0 4 155 50 50 255" << std::endl; + ofd << inpt.size() << std::endl; + for (size_t kr=0; kr<inpt.size(); ++kr) + ofd << inpt[kr]->getPoint() << std::endl; + ofd << "400 1 0 4 50 155 50 255" << std::endl; + ofd << outpt.size() << std::endl; + for (size_t kr=0; kr<outpt.size(); ++kr) + ofd << outpt[kr]->getPoint() << std::endl; +#endif + + int num_in_lin, num_in_cub; + double avd_lin, avd_cub; + analyseCylRotate(cyl, tol, avd, num2, avd_lin, num_in_lin, + avd_cub, num_in_cub, cone); + analyseCylProject(cyl, tol, configs); + if (cone.get()) + { + double maxd2, avd2; + int num3, num3_2; + vector<RevEngPoint*> inpt2, outpt2; + vector<pair<double, double> > dist_ang2; + vector<double> parvals2; + RevEngUtils::distToSurf(group_points_.begin(), group_points_.end(), + cone, tol, maxd2, avd2, num3, num3_2, inpt2, outpt2, + parvals2, dist_ang2, angtol); +#ifdef DEBUG_CYL + std::ofstream ofsc("cone_cyl.g2"); + shared_ptr<Cone> cone2(cone->clone()); + double diag = bbox_.low().dist(bbox_.high()); + cone2->setParamBoundsV(-0.5*diag,0.5*diag); + cone2->writeStandardHeader(ofsc); + cone2->write(ofsc); + std::ofstream ofdc("in_out_cone_cyl.g2"); + ofdc << "400 1 0 4 155 50 50 255" << std::endl; + ofdc << inpt2.size() << std::endl; + for (size_t kr=0; kr<inpt2.size(); ++kr) + ofdc << inpt2[kr]->getPoint() << std::endl; + ofdc << "400 1 0 4 50 155 50 255" << std::endl; + ofdc << outpt.size() << std::endl; + for (size_t kr=0; kr<outpt2.size(); ++kr) + ofdc << outpt2[kr]->getPoint() << std::endl; +#endif + int stop_cone = 1; + } + + if (configs.size() > 1 && (!hasSurface())) + { + // Split point group and try again + int keep_ix = -1; + int keep_nmb = 0; + for (size_t ki=0; ki<configs.size(); ++ki) + if ((int)configs[ki].size() > keep_nmb) + { + keep_nmb = (int)configs[ki].size(); + keep_ix = (int)ki; + } + + for (size_t ki=0; ki<configs.size(); ++ki) + { + if ((int)ki == keep_ix) + continue; + + extractSpesPoints(configs[ki], out_groups); + } + + // Check that the remaing point cloud is connected + splitRegion(out_groups); + + if (hasSurface()) + { + for (size_t ki=0; ki<associated_sf_.size(); ++ki) + prevsfs.push_back(associated_sf_[ki]); + clearSurface(); + } + + updateInfo(tol, angtol); + repeat = true; + } + else + { + int num = (int)group_points_.size(); + if (num2 > min_pt && num2 > num/2) + { + // Check for deviant points at the boundary + vector<RevEngPoint*> dist_points; + identifyDistPoints(dist_ang, tol, maxd, avd, dist_points); + extractSpesPoints(dist_points, out_groups, true); + if (out_groups.size() > 0) + { + // Ensure connected region + vector<vector<RevEngPoint*> > separate_groups; + splitRegion(separate_groups); + if (separate_groups.size() > 0) + { + out_groups.insert(out_groups.end(), separate_groups.begin(), + separate_groups.end()); + } + + shared_ptr<Cylinder> cyl_in = computeCylinder(group_points_, tol); + vector<RevEngPoint*> inpt_in, outpt_in; + vector<pair<double, double> > dist_ang_in; + vector<double> parvals_in; + double maxd_in, avd_in; + int num2_in, num2_in2; + RevEngUtils::distToSurf(group_points_.begin(), group_points_.end(), + cyl_in, tol, maxd_in, avd_in, num2_in, num2_in2, + inpt_in, outpt_in, parvals_in, dist_ang_in, angtol); + + +#ifdef DEBUG_CYL + std::ofstream ofd2("in_out_cylinder2.g2"); + ofd2 << "400 1 0 4 155 50 50 255" << std::endl; + ofd2 << inpt_in.size() << std::endl; + for (size_t kr=0; kr<inpt_in.size(); ++kr) + ofd2 << inpt_in[kr]->getPoint() << std::endl; + ofd2 << "400 1 0 4 50 155 50 255" << std::endl; + ofd2 << outpt_in.size() << std::endl; + for (size_t kr=0; kr<outpt_in.size(); ++kr) + ofd2 << outpt_in[kr]->getPoint() << std::endl; +#endif + std::swap(cyl, cyl_in); + std::swap(num2, num2_in); + std::swap(num2_2, num2_in2); + std::swap(avd, avd_in); + std::swap(maxd, maxd_in); + std::swap(parvals, parvals_in); + std::swap(dist_ang, dist_ang_in); + } + } + + double maxd_init, avd_init; + int num_init, num_init2; + getAccuracy(maxd_init, avd_init, num_init, num_init2); + int sf_flag = defineSfFlag(0, tol, num2, num2_2, + avd, true); + if (sf_flag < ACCURACY_POOR) + { + bool OK = true; + double acc_fac = 1.5; + if (associated_sf_.size() > 0) + { + int sfcode; + int sftype = associated_sf_[0]->instanceType(sfcode); + double ang = (sftype == Class_Plane) ? + normalcone_.angle() : M_PI; + double ang_lim = 0.1*M_PI; + + // Check with current approximating surface + if (surfflag_ == ACCURACY_OK && sf_flag > surfflag_) + OK = false; + else if (prefer_elementary == ALWAYS_ELEM || + prefer_elementary == PREFER_ELEM) + { + if (!(ang > ang_lim && (num2 < num_init || + (avd < avd_init && + num2 < acc_fac*num_init)))) + OK = false; + } + else + { + if (!(num2 < num_init || + (avd < avd_init && num2 < acc_fac*num_init))) + OK = true; + } + if (sf_flag == ACCURACY_OK && surfflag_ > ACCURACY_OK) + OK = true; + } + + if (OK) + { + found = true; + for (size_t kh=0; kh<group_points_.size(); ++kh) + { + group_points_[kh]->setPar(Vector2D(parvals[2*kh],parvals[2*kh+1])); + group_points_[kh]->setSurfaceDist(dist_ang[kh].first, dist_ang[kh].second); + } + setAccuracy(maxd, avd, num2, num2_2); + + // // Limit cylinder with respect to bounding box + // double gap = 1.0e-6; + // Point xdir(1.0, 0.0, 0.0); + // Point ydir(0.0, 1.0, 0.0); + // Point zdir(0.0, 0.0, 1.0); + // Point bbdiag = high - low; + // CompositeModelFactory factory(gap, gap, 10.0*gap, 0.01, 0.05); + // shared_ptr<SurfaceModel> boxmod(factory.createFromBox(low-2.0*bbdiag, xdir, ydir, + // 5*bbdiag[0], 5*bbdiag[1], + // 5*bbdiag[2])); + // vector<shared_ptr<ParamSurface> > sfs; + // sfs.push_back(cyl); + // shared_ptr<SurfaceModel> cylmod(new SurfaceModel(gap, gap, 10.0*gap, 0.01, + // 0.05, sfs)); + // vector<shared_ptr<SurfaceModel> > divcyl = cylmod->splitSurfaceModels(boxmod); + +#ifdef DEBUG + std::cout << "Cylinder. N1: " << num << ", N2: " << num2 << ", max: " << maxd << ", av: " << avd << std::endl; +#endif + shared_ptr<HedgeSurface> hedge(new HedgeSurface(cyl, this)); + for (size_t kh=0; kh<associated_sf_.size(); ++kh) + prevsfs.push_back(associated_sf_[kh]); + setHedge(hedge.get()); + hedgesfs.push_back(hedge); + setSurfaceFlag(sf_flag); + // for (int ka=0; ka<divcyl[0]->nmbEntities(); ++ka) + // { + // shared_ptr<ParamSurface> cyl2 = divcyl[0]->getSurface(ka); + // shared_ptr<HedgeSurface> hedge(new HedgeSurface(cyl2, this)); + // for (size_t kh=0; kh<associated_sf_.size(); ++kh) + // prevsfs.push_back(associated_sf_[kh]); + // associated_sf_.push_back(hedge.get()); + // hedgesfs.push_back(hedge); + + } + } + } + if (!basesf_.get() || + (num2 >= num_in_base_ && avd < avdist_base_)) + setBaseSf(cyl, maxd, avd, num2, num2_2); + + return found; +} + +//=========================================================================== +shared_ptr<Cylinder> +RevEngRegion::computeCylinder(vector<RevEngPoint*>& points, double tol) +//=========================================================================== +{ + // Cylinder orientation by covariance matrix of normal vectors + Point axis; + Point Cx; + Point Cy; + vector<pair<vector<RevEngPoint*>::iterator, + vector<RevEngPoint*>::iterator> > group; + group.push_back(std::make_pair(points.begin(), points.end())); + RevEngUtils::computeAxis(group, axis, Cx, Cy); + + Point low = bbox_.low(); + Point high = bbox_.high(); + //double len = low.dist(high); + double rad; + Point pnt; + RevEngUtils::computeCylPosRadius(group, low, high, + axis, Cx, Cy, pnt, rad); + shared_ptr<Cylinder> cyl(new Cylinder(rad, pnt, axis, Cy)); +#ifdef DEBUG_CYL + std::ofstream of("cylinder_compute.g2"); + cyl->writeStandardHeader(of); + cyl->write(of); +#endif + return cyl; +} + +//=========================================================================== +void RevEngRegion::analyseCylProject(shared_ptr<Cylinder> cyl, double tol, + vector<vector<RevEngPoint*> >& configs) +//=========================================================================== +{ +#ifdef DEBUG_CYL + std::ofstream of("projected_pts_cyl.g2"); +#endif + + vector<pair<vector<RevEngPoint*>::iterator, + vector<RevEngPoint*>::iterator> > group; + group.push_back(std::make_pair(group_points_.begin(), group_points_.end())); + Point pnt = cyl->location(); + Point axis, Cx, Cy; + cyl->getCoordinateAxes(Cx, Cy, axis); + double rad = cyl->getRadius(); + vector<Point> projected; + double maxdp, avdp; + RevEngUtils::projectToPlane(group, axis, pnt, projected, maxdp, avdp); + shared_ptr<Circle> circ(new Circle(rad, pnt, axis, Cx)); + shared_ptr<SplineCurve> spl; + Point xpos; + vector<double> param; + curveApprox(projected, tol, circ, param, spl, xpos); + +#ifdef DEBUG_CYL + of << "400 1 0 4 255 0 0 255" << std::endl; + of << projected.size() << std::endl; + for (size_t kr=0; kr<projected.size(); ++kr) + of << projected[kr] << std::endl; + circ->writeStandardHeader(of); + circ->write(of); + spl->writeStandardHeader(of); + spl->write(of); +#endif + + double maxdc, avdc, maxds, avds; + int num_inc, num_ins; + RevEngUtils::distToCurve(projected, circ, tol, maxdc, avdc, num_inc); + RevEngUtils::distToCurve(projected, spl, tol, maxds, avds, num_ins); + + double len = bbox_.low().dist(bbox_.high()); + if (maxds < maxdc && num_ins > num_inc && + num_ins > (int)group_points_.size()/4 && rad < 2.0*len) + { + // Investigate point configuration + configSplit(group_points_, param, cyl, spl, maxds, configs); +#ifdef DEBUG_CYL + std::ofstream ofconf("conf_groups.g2"); + for (size_t ki=0; ki<configs.size(); ++ki) + { + ofconf << "400 1 0 0" << std::endl; + ofconf << configs[ki].size() << std::endl; + for (size_t kr=0; kr<configs[ki].size(); ++kr) + ofconf << configs[ki][kr]->getPoint() << std::endl; + } +#endif + } + + if (configs.size() <= 1 && (num_ins >= num_inc && avds <= avdc) && + (num_ins > (int)group_points_.size()/2 && avds < tol) && + (!sweep_.get() || sweep_->type_ != 1 || + (sweep_->num_in_ < num_ins && sweep_->avdist_ > avds))) + { + // Possible linear sweep + Point pt1 = pnt - len*axis; + Point pt2 = pnt + len*axis; + sweep_ = shared_ptr<SweepData>(new SweepData(1, spl, pt1, pt2, maxds, avds, num_ins)); + } + int stop_break = 1; + } + + +//=========================================================================== +bool RevEngRegion::defineConeFromCyl(shared_ptr<Cylinder> cyl, double tol, + double angtol, int min_pt_reg, + double avdist, int num_in, int num2_in, + vector<shared_ptr<HedgeSurface> >& hedgesfs, + vector<vector<RevEngPoint*> >& out_groups, + vector<RevEngPoint*>& single_pts) +//=========================================================================== +{ +#ifdef DEBUG_CYL + std::ofstream of("rotated_pts.g2"); +#endif + + Point pnt = cyl->location(); + Point axis, Cx, Cy; + cyl->getCoordinateAxes(Cx, Cy, axis); + vector<Point> rotated; + vector<pair<vector<RevEngPoint*>::iterator, + vector<RevEngPoint*>::iterator> > group; + group.push_back(std::make_pair(group_points_.begin(), group_points_.end())); + double len = bbox_.low().dist(bbox_.high()); + RevEngUtils::rotateToPlane(group, Cy, axis, pnt, rotated); + shared_ptr<Line> line(new Line(pnt, axis)); + line->setParameterInterval(-len, len); + Point pt1 = line->ParamCurve::point(-len); + Point pt2 = line->ParamCurve::point(len); + shared_ptr<SplineCurve> line_cv(new SplineCurve(pt1, -len, pt2, len)); + shared_ptr<SplineCurve> crv; + RevEngUtils::curveApprox(rotated, line_cv, 2, 2, crv); + double maxdcrv, avdcrv; + int num_in_crv; + vector<double> dist; + RevEngUtils::distToCurve(rotated, crv, tol, maxdcrv, avdcrv, num_in_crv, dist); +#ifdef DEBUG_CYL + of << "400 1 0 4 255 0 0 255" << std::endl; + of << rotated.size() << std::endl; + for (size_t kr=0; kr<rotated.size(); ++kr) + of << rotated[kr] << std::endl; + + crv->writeStandardHeader(of); + crv->write(of); +#endif + + if (avdcrv > avdist || num_in_crv < num2_in) + return false; // No gain in replacing the cylinder with a cone + + // Identify distant points + double dlim = std::max(2.0*tol, 2.0*avdcrv); + vector<RevEngPoint*> dist_pts; + vector<RevEngPoint*> remaining; + vector<Point> rotated2; + for (size_t ki=0; ki<group_points_.size(); ++ki) + { + if (dist[ki] > dlim) + dist_pts.push_back(group_points_[ki]); + else + { + remaining.push_back(group_points_[ki]); + rotated2.push_back(rotated[ki]); + } + } +#ifdef DEBUG_CYL + std::ofstream of3("split_group.g2"); + if (remaining.size() > 0) + { + of3 << "400 1 0 4 255 0 0 255" << std::endl; + of3 << remaining.size() << std::endl; + for (size_t kr=0; kr<remaining.size(); ++kr) + of3 << remaining[kr]->getPoint() << std::endl; + } + if (dist_pts.size() > 0) + { + of3 << "400 1 0 4 0 255 0 255" << std::endl; + of3 << dist_pts.size() << std::endl; + for (size_t kr=0; kr<dist_pts.size(); ++kr) + of3 << dist_pts[kr]->getPoint() << std::endl; + } +#endif + if (remaining.size() < 0.5*group_points_.size()) + return false; + + // Define cone + shared_ptr<SplineCurve> crv2; + RevEngUtils::curveApprox(rotated2, line_cv, 2, 2, crv2); + double tclose, dclose; + Point ptclose; + crv2->closestPoint(pnt, crv2->startparam(), crv2->endparam(), tclose, + ptclose, dclose); + vector<Point> der(2); + crv2->point(der, tclose, 1); + double phi = der[1].angle(axis); + + // Check sign of angle + Point pnt2 = pnt + 0.1*len*axis; + double tclose2, dclose2; + Point ptclose2; + crv2->closestPoint(pnt2, crv2->startparam(), crv2->endparam(), tclose2, + ptclose2, dclose2); + if (dclose2 < dclose) + phi *= -1; + + shared_ptr<Cone> cone(new Cone(dclose, pnt, axis, Cy, phi)); +#ifdef DEBUG_CYL + std::ofstream of2("cone_from_rotate.g2"); + double t1 = crv2->startparam(); + double t2 = crv2->endparam(); + cone->setParamBoundsV(t1-0.1*(t2-t1), t2+0.1*(t2-t1)); + cone->writeStandardHeader(of2); + cone->write(of2); +#endif + + // Check accuracy + bool found = false; + double maxdistco, avdistco; + int num_insideco, num2_insideco; + vector<pair<double, double> > dist_ang; + vector<double> parvals; + vector<RevEngPoint*> inco, outco; + RevEngUtils::distToSurf(remaining.begin(), remaining.end(), + cone, tol, maxdistco, avdistco, + num_insideco, num2_insideco, + inco, outco, parvals, dist_ang, angtol); + int sf_flag = defineSfFlag(remaining.size(), 0, tol, num_insideco, + num2_insideco, avdistco, true); + if (sf_flag < ACCURACY_POOR) + { + bool OK = true; + double acc_fac = 1.5; + double frac = (double)remaining.size()/(double)group_points_.size(); + if (associated_sf_.size() > 0) + { + double maxd_init, avd_init; + int num_init, num_init2; + getAccuracy(maxd_init, avd_init, num_init, num_init2); + if (surfflag_ == ACCURACY_OK && sf_flag > surfflag_) + OK = false; + else + { + if (!((double)num_insideco < frac*(double)num_init || + (avdistco < avd_init && + (double)num_insideco < acc_fac*frac*(double)num_init))) + OK = true; + } + if (sf_flag == ACCURACY_OK && surfflag_ > ACCURACY_OK) + OK = true; + } + + if (OK) + { + found = true; + std::swap(group_points_, remaining); + for (size_t kh=0; kh<group_points_.size(); ++kh) + { + group_points_[kh]->setPar(Vector2D(parvals[2*kh],parvals[2*kh+1])); + group_points_[kh]->setSurfaceDist(dist_ang[kh].first, dist_ang[kh].second); + } + setAccuracy(maxdistco, avdistco, num_insideco, num2_insideco); + shared_ptr<HedgeSurface> hedge(new HedgeSurface(cone, this)); + + setHedge(hedge.get()); + hedgesfs.push_back(hedge); + setSurfaceFlag(sf_flag); + + // Make sure that the distant points are connected + vector<vector<RevEngPoint*> > separate_groups; + vector<RevEngPoint*> dummy; + connectedGroups(dist_pts, separate_groups, false, dummy); + if (separate_groups.size() > 0) + { + for (size_t kh=0; kh<separate_groups.size(); ++kh) + { +#ifdef DEBUG_CYL + std::ofstream of4("curr_sep_group.g2"); + of4 << "400 1 0 4 0 0 255 255" << std::endl; + of4 << separate_groups[kh].size() << std::endl; + for (size_t kr=0; kr<separate_groups[kh].size(); ++kr) + of4 << separate_groups[kh][kr]->getPoint() << std::endl; +#endif + // Check if the group can be added to the current region given + // the updated cone + vector<RevEngPoint*> in2, out2; + vector<pair<double,double> > dist_ang2; + vector<double> parvals2; + int nmb_in2, nmb2_in2; + double maxd2, avd2; + RevEngUtils::distToSurf(separate_groups[kh].begin(), + separate_groups[kh].end(), + cone, tol, maxd2, avd2, nmb_in2, nmb2_in2, + in2, out2, parvals2, dist_ang2, angtol); + int sf_flag2 = defineSfFlag(separate_groups[kh].size(), 0, tol, + nmb_in2, nmb2_in2, avd2, true); + + if (sf_flag2 <= sf_flag) + { + for (size_t kr=0; kr<separate_groups[kh].size(); ++kr) + { + separate_groups[kh][kr]->setPar(Vector2D(parvals2[2*kr], + parvals2[2*kr+1])); + separate_groups[kh][kr]->setSurfaceDist(dist_ang2[kr].first, + dist_ang2[kr].second); + } + (void)addPointsToGroup(separate_groups[kh], tol, angtol); + } + else if (separate_groups[kh].size() == 1) + { + separate_groups[kh][0]->unsetRegion(); + single_pts.push_back(separate_groups[kh][0]); + } + else + { + for (size_t kr=0; kr<separate_groups[kh].size(); ++kr) + separate_groups[kh][kr]->unsetRegion(); + out_groups.push_back(separate_groups[kh]); + } + } + } + } + } + return found; + } + +//=========================================================================== +void RevEngRegion::analyseCylRotate(shared_ptr<Cylinder> cyl, double tol, + double avdist, int num_in, + double& avdist_lin, int& num_in_lin, + double& avdist_cub, int& num_in_cub, + shared_ptr<Cone>& cone) +//=========================================================================== +{ +#ifdef DEBUG_CYL + std::ofstream of("rotated_pts_cyl.g2"); +#endif + + vector<pair<vector<RevEngPoint*>::iterator, + vector<RevEngPoint*>::iterator> > group; + group.push_back(std::make_pair(group_points_.begin(), group_points_.end())); + Point pnt = cyl->location(); + Point axis, Cx, Cy; + cyl->getCoordinateAxes(Cx, Cy, axis); + //double rad = cyl->getRadius(); + vector<Point> rotated; + RevEngUtils::rotateToPlane(group, Cy, axis, pnt, rotated); + double len = bbox_.low().dist(bbox_.high()); +#ifdef DEBUG_CYL + of << "400 1 0 4 255 0 0 255" << std::endl; + of << rotated.size() << std::endl; + for (size_t kr=0; kr<rotated.size(); ++kr) + of << rotated[kr] << std::endl; + of << "410 1 0 4 0 0 255 255" << std::endl; + of << "1" << std::endl; + of << pnt-0.5*len*axis << " " << pnt+0.5*len*axis << std::endl; + of << "410 1 0 4 0 255 0 255" << std::endl; + of << "1" << std::endl; + of << pnt-0.5*len*Cy << " " << pnt+0.5*len*Cy << std::endl; +#endif + + shared_ptr<Line> line(new Line(pnt, axis)); + line->setParameterInterval(-len, len); + shared_ptr<SplineCurve> line2; + RevEngUtils::curveApprox(rotated, line, 2, 2, line2); + vector<Point> der(2); + line2->point(der, 0.0, 1); + + Point pt1 = line->ParamCurve::point(-len); + Point pt2 = line->ParamCurve::point(len); + shared_ptr<SplineCurve> line_cv(new SplineCurve(pt1, -len, pt2, len)); + shared_ptr<SplineCurve> cv1, cv2; + RevEngUtils::curveApprox(rotated, line_cv, 2, 2, cv1); + RevEngUtils::curveApprox(rotated, line_cv, 4, 8, cv2); + double maxdcv1, maxdcv2; + RevEngUtils::distToCurve(rotated, cv1, tol, maxdcv1, avdist_lin, num_in_lin); + RevEngUtils::distToCurve(rotated, cv2, tol, maxdcv2, avdist_cub, num_in_cub); +#ifdef DEBUG_CYL + cv1->writeStandardHeader(of); + cv1->write(of); + cv2->writeStandardHeader(of); + cv2->write(of); +#endif + + // Check if a cone is feasible + double cfac = 1.2; + if (avdist_lin < cfac*std::min(avdist_cub, avdist) && + cfac*num_in_lin > (double)std::max(num_in_cub, num_in)) + { + double tclose, dclose; + Point ptclose; + cv1->closestPoint(pnt, cv1->startparam(), cv1->endparam(), tclose, + ptclose, dclose); + vector<Point> der(2); + cv1->point(der, tclose, 1); + double phi = der[1].angle(axis); + + // Check sign of angle + Point pnt2 = pnt + 0.1*len*axis; + double tclose2, dclose2; + Point ptclose2; + cv1->closestPoint(pnt2, cv1->startparam(), cv1->endparam(), tclose2, + ptclose2, dclose2); + if (dclose2 < dclose) + phi *= -1; + + cone = shared_ptr<Cone>(new Cone(dclose, pnt, axis, Cy, phi)); +#ifdef DEBUG_CYL + std::ofstream of2("cone_from_rotate.g2"); + double t1 = cv1->startparam(); + double t2 = cv1->endparam(); + cone->setParamBoundsV(t1-0.1*(t2-t1), t2+0.1*(t2-t1)); + cone->writeStandardHeader(of2); + cone->write(of2); +#endif + } + + int stop_break = 1; +} + + + +//=========================================================================== +bool RevEngRegion::extractLinearSweep(double tol, int min_pt, int min_pt_reg, + double angtol, int prefer_elementary, + std::vector<shared_ptr<HedgeSurface> >& hedgesfs, + std::vector<HedgeSurface*>& prevsfs) +//=========================================================================== +{ + if (!sweep_.get()) + return false; + + if (sweep_->type_ != 1) + return false; + + bool found = false; + shared_ptr<SplineSurface> surf; + + vector<pair<shared_ptr<ElementarySurface>, RevEngRegion*> > adj_elem, adj_elem_base; + getAdjacentElemInfo(adj_elem, adj_elem_base); + + SweepSurfaceCreator sweep; + shared_ptr<SplineCurve> along(new SplineCurve(sweep_->location_, sweep_->added_info_)); + Point mid = 0.5*(sweep_->location_ + sweep_->added_info_); + surf = shared_ptr<SplineSurface>(sweep.linearSweptSurface(*along, + *sweep_->profile_, mid)); + if (!surf.get()) + return false; +#ifdef DEBUG_EXTRACT + std::ofstream of3("sweep.g2"); + along->writeStandardHeader(of3); + along->write(of3); + sweep_->profile_->writeStandardHeader(of3); + sweep_->profile_->write(of3); + surf->writeStandardHeader(of3); + surf->write(of3); + of3 << "400 1 0 4 255 0 0 255" << std::endl; + of3 << "1" << std::endl; + of3 << sweep_->location_ << std::endl; +#endif + + // Check accuracy + double maxd, avd; + int num2, num2_2; + vector<RevEngPoint*> inpt, outpt; + vector<pair<double, double> > dist_ang; + vector<double> parvals; + RevEngUtils::distToSurf(group_points_.begin(), group_points_.end(), + surf, tol, maxd, avd, num2, num2_2, inpt, outpt, + parvals, dist_ang, angtol); +#ifdef DEBUG_EXTRACT + std::ofstream ofd("in_out_surf.g2"); + ofd << "400 1 0 4 155 50 50 255" << std::endl; + ofd << inpt.size() << std::endl; + for (size_t kr=0; kr<inpt.size(); ++kr) + ofd << inpt[kr]->getPoint() << std::endl; + ofd << "400 1 0 4 50 155 50 255" << std::endl; + ofd << outpt.size() << std::endl; + for (size_t kr=0; kr<outpt.size(); ++kr) + ofd << outpt[kr]->getPoint() << std::endl; +#endif + //int num = (int)group_points_.size(); + double maxd_init, avd_init; + int num_init, num_init2; + getAccuracy(maxd_init, avd_init, num_init, num_init2); + int sf_flag = defineSfFlag(0, tol, num2, num2_2, avd, false); + if (sf_flag < ACCURACY_POOR) + { + bool OK = true; + if (associated_sf_.size() > 0) + { + // Check with current approximating surface + double acc_fac1 = 1.25; + double acc_fac2 = 0.75; + if (surfflag_ == ACCURACY_OK && sf_flag > surfflag_) + OK = false; + else if (prefer_elementary == ALWAYS_ELEM) + OK = false; + else if (prefer_elementary == PREFER_ELEM && + ((double)num2 < acc_fac1*num_init || + avd > acc_fac2*avd_init)) + OK = false; + else if (prefer_elementary == BEST_ACCURACY && + (num2 < num_init || avd > avd_init)) + OK = false; + } + + if (OK) + { + found = true; + for (size_t kh=0; kh<group_points_.size(); ++kh) + { + group_points_[kh]->setPar(Vector2D(parvals[2*kh],parvals[2*kh+1])); + group_points_[kh]->setSurfaceDist(dist_ang[kh].first, dist_ang[kh].second); + } + setAccuracy(maxd, avd, num2, num2_2); +#ifdef DEBUG + std::cout << "Linear swept surface. N1: " << num << ", N2: " << num2 << ", max: " << maxd << ", av: " << avd << std::endl; +#endif + + shared_ptr<HedgeSurface> hedge(new HedgeSurface(surf, this)); + hedge->setLinearSweepInfo(sweep_->profile_, sweep_->location_, sweep_->added_info_); + for (size_t kh=0; kh<associated_sf_.size(); ++kh) + prevsfs.push_back(associated_sf_[kh]); + setHedge(hedge.get()); + hedgesfs.push_back(hedge); + setSurfaceFlag(sf_flag); + } + } + + return found; + } + +//=========================================================================== +shared_ptr<SplineSurface> +RevEngRegion::computeLinearSwept(double tol, shared_ptr<SplineCurve>& profile, + Point& pt1, Point& pt2) +//=========================================================================== +{ + // Axis by covariance matrix of normal vectors + Point axis; + Point Cx; + Point Cy; + vector<pair<vector<RevEngPoint*>::iterator, + vector<RevEngPoint*>::iterator> > group; + group.push_back(std::make_pair(group_points_.begin(), group_points_.end())); + RevEngUtils::computeAxis(group, axis, Cx, Cy); + + // Point on axis + Point low = bbox_.low(); + Point high = bbox_.high(); + double len = low.dist(high); + double rad; + Point pnt; + RevEngUtils::computeCylPosRadius(group, low, high, + axis, Cx, Cy, pnt, rad); + + // Project the points onto the defined plane + vector<Point> projected; + double maxdp, avdp; + RevEngUtils::projectToPlane(group, axis, pnt, projected, maxdp, avdp); + + // Approximate the projected point cloud with a spline curve + shared_ptr<Circle> circ(new Circle(rad, pnt, axis, Cx)); + Point xpos; + vector<double> param; + curveApprox(projected, tol, circ, param, profile, xpos); + + pt1 = pnt - len*axis; + pt2 = pnt + len*axis; + Point mid = 0.5*(pt1 + pt2); + + SweepSurfaceCreator sweep; + shared_ptr<SplineCurve> along(new SplineCurve(pt1, pt2)); + shared_ptr<SplineSurface> swept_surf(sweep.linearSweptSurface(*along, *profile, mid)); + + return swept_surf; +} + +//=========================================================================== +bool RevEngRegion::extractSphere(Point mainaxis[3], + double tol, int min_pt, int min_pt_reg, + double angtol, int prefer_elementary, + vector<shared_ptr<HedgeSurface> >& hedgesfs, + vector<HedgeSurface*>& prevsfs, + vector<vector<RevEngPoint*> >& out_groups) +//=========================================================================== +{ + bool found = false; + int min_nmb = 20; + //double eps = 1.0e-6; + if ((int)group_points_.size() < min_nmb) + return false; + + vector<pair<shared_ptr<ElementarySurface>, RevEngRegion*> > adj_elem, adj_elem_base; + getAdjacentElemInfo(adj_elem, adj_elem_base); + + Point adj_axis; + int num_pt_adj = 0; + for (size_t ki=0; ki<adj_elem.size(); ++ki) + { + int type = adj_elem[ki].first->instanceType(); + if (type == Class_Cylinder || type == Class_Cone) + { + if (adj_elem[ki].second->numPoints() > num_pt_adj) + { + adj_axis = adj_elem[ki].first->direction(); + num_pt_adj = adj_elem[ki].second->numPoints(); + } + } + } + + shared_ptr<Sphere> sphere = computeSphere(mainaxis, adj_axis, group_points_); + if (!sphere.get()) + return false; +#ifdef DEBUG_EXTRACT + std::ofstream ofs("sph.g2"); + sphere->writeStandardHeader(ofs); + sphere->write(ofs); +#endif + // Check accuracy + double maxd, avd; + int num2, num2_2; + vector<RevEngPoint*> inpt, outpt; + vector<pair<double, double> > dist_ang; + vector<double> parvals; + RevEngUtils::distToSurf(group_points_.begin(), group_points_.end(), + sphere, tol, maxd, avd, num2, num2_2, inpt, outpt, + parvals, dist_ang, angtol); +#ifdef DEBUG_EXTRACT + std::ofstream ofd("in_out_sphere.g2"); + ofd << "400 1 0 4 155 50 50 255" << std::endl; + ofd << inpt.size() << std::endl; + for (size_t kr=0; kr<inpt.size(); ++kr) + ofd << inpt[kr]->getPoint() << std::endl; + ofd << "400 1 0 4 50 155 50 255" << std::endl; + ofd << outpt.size() << std::endl; + for (size_t kr=0; kr<outpt.size(); ++kr) + ofd << outpt[kr]->getPoint() << std::endl; +#endif + + if (inpt.size() > group_points_.size()/2 && (int)inpt.size() > min_nmb) + { + shared_ptr<Sphere> sphere_in = computeSphere(mainaxis, adj_axis, inpt); + vector<RevEngPoint*> inpt_in, outpt_in; //, inpt2, outpt2; + vector<pair<double, double> > dist_ang_in; + vector<double> parvals_in; + double maxd_in, avd_in; + int num2_in, num2_in2; + RevEngUtils::distToSurf(group_points_.begin(), group_points_.end(), + sphere_in, tol, maxd_in, avd_in, num2_in, num2_in2, + inpt_in, outpt_in, parvals_in, dist_ang_in, angtol); + +#ifdef DEBUG_EXTRACT + std::ofstream ofd2("in_out_sphere2.g2"); + ofd2 << "400 1 0 4 155 50 50 255" << std::endl; + ofd2 << inpt_in.size() << std::endl; + for (size_t kr=0; kr<inpt_in.size(); ++kr) + ofd2 << inpt_in[kr]->getPoint() << std::endl; + ofd2 << "400 1 0 4 50 155 50 255" << std::endl; + ofd2 << outpt_in.size() << std::endl; + for (size_t kr=0; kr<outpt_in.size(); ++kr) + ofd2 << outpt_in[kr]->getPoint() << std::endl; +#endif + + if (num2_in > num2 || avd_in < avd) + { + std::swap(sphere, sphere_in); + std::swap(num2, num2_in); + std::swap(num2_2, num2_in2); + std::swap(avd, avd_in); + std::swap(maxd, maxd_in); + std::swap(parvals, parvals_in); + std::swap(dist_ang, dist_ang_in); + // std::cout << "Sphere swap" << std::endl; + // std::cout << group_points_.size() << " " << num2_in; + // std::cout << " " << num2 << " " << avd_in << " " << avd; + // std::cout << " " << maxd_in << " " << maxd << std::endl; + } + } + + //int num = (int)group_points_.size(); + double maxd_init, avd_init; + int num_init, num_init2; + getAccuracy(maxd_init, avd_init, num_init, num_init2); + int sf_flag = defineSfFlag(0, tol, num2, num2_2, + avd, false); + if (sf_flag < ACCURACY_POOR) + { + bool OK = true; + if (associated_sf_.size() > 0) + { + // Check with current approximating surface + double acc_fac1 = 1.25; + double acc_fac2 = 0.75; + if (surfflag_ == ACCURACY_OK && sf_flag > surfflag_) + OK = false; + else if (surfflag_ < ACCURACY_POOR && sf_flag >= ACCURACY_POOR) + OK = false; + else if (prefer_elementary == ALWAYS_ELEM) + OK = false; + else if (prefer_elementary == PREFER_ELEM && + ((double)num2 < acc_fac1*num_init || + avd > acc_fac2*avd_init)) + OK = false; + else if (prefer_elementary == BEST_ACCURACY && + (num2 < num_init || avd > avd_init)) + OK = false; + if (sf_flag == ACCURACY_OK && surfflag_ > ACCURACY_OK) + OK = true; + } + + if (OK) + { + found = true; + for (size_t kh=0; kh<group_points_.size(); ++kh) + { + group_points_[kh]->setPar(Vector2D(parvals[2*kh],parvals[2*kh+1])); + group_points_[kh]->setSurfaceDist(dist_ang[kh].first, dist_ang[kh].second); + } + setAccuracy(maxd, avd, num2, num2_2); +#ifdef DEBUG + std::cout << "Sphere. N1: " << num << ", N2: " << num2 << ", max: " << maxd << ", av: " << avd << std::endl; +#endif + shared_ptr<HedgeSurface> hedge(new HedgeSurface(sphere, this)); + for (size_t kh=0; kh<associated_sf_.size(); ++kh) + prevsfs.push_back(associated_sf_[kh]); + setHedge(hedge.get()); + hedgesfs.push_back(hedge); + setSurfaceFlag(sf_flag); + } + } + if (!basesf_.get() || + (num2 >= num_in_base_ && avd < avdist_base_)) + setBaseSf(sphere, maxd, avd, num2, num2_2); + + return found; +} + +//=========================================================================== +shared_ptr<Sphere> RevEngRegion::computeSphere(Point mainaxis[3], + Point adj_axis, + vector<RevEngPoint*>& points) +//=========================================================================== +{ + vector<pair<vector<RevEngPoint*>::iterator, + vector<RevEngPoint*>::iterator> > group; + group.push_back(std::make_pair(points.begin(), points.end())); + Point centre; + double radius; + try { + RevEngUtils::computeSphereProp(group, centre, radius); + } + catch (...) + { + shared_ptr<Sphere> dummy; + return dummy; + } + + Point z_axis; + int ix = -1; + double minang = M_PI; + if (adj_axis.dimension() > 0) + z_axis = adj_axis; + else + { + Point norm = normalcone_.centre(); + for (int ka=0; ka<3; ++ka) + { + double ang = mainaxis[ka].angle(norm); + ang = std::min(ang, M_PI-ang); + if (ang < minang) + { + minang = ang; + ix = ka; + } + } + z_axis = mainaxis[ix]; + } + + // Define x-axis + ix = -1; + for (int ka=0; ka<3; ++ka) + { + double ang = mainaxis[ka].angle(z_axis); + ang = std::min(ang, M_PI-ang); + if (ang < minang) + { + minang = ang; + ix = ka; + } + } + + Point Cy = mainaxis[(ix+1)%3].cross(z_axis); + Point Cx = z_axis.cross(Cy); + + shared_ptr<Sphere> sph(new Sphere(radius, centre, z_axis, Cx)); + //cyl->setParamBoundsV(-len, len); + return sph; +} + +//=========================================================================== +bool RevEngRegion::extractCone(double tol, int min_pt, int min_pt_reg, + double angtol, int prefer_elementary, + vector<shared_ptr<HedgeSurface> >& hedgesfs, + vector<HedgeSurface*>& prevsfs, + vector<vector<RevEngPoint*> >& out_groups) +//=========================================================================== +{ + bool found = false; + int min_nmb = 20; + //double eps = 1.0e-6; + double minang = 0.05; + if ((int)group_points_.size() < min_nmb) + return false; + + vector<pair<shared_ptr<ElementarySurface>, RevEngRegion*> > adj_elem, adj_elem_base; + getAdjacentElemInfo(adj_elem, adj_elem_base); + + Point apex; + shared_ptr<Cone> cone = computeCone(group_points_, apex); +#ifdef DEBUG_EXTRACT + std::ofstream ofs("conesf.g2"); + cone->writeStandardHeader(ofs); + cone->write(ofs); +#endif + + // Check accuracy + double maxd, avd; + int num2, num2_2; + vector<RevEngPoint*> inpt, outpt; + vector<pair<double, double> > dist_ang; + vector<double> parvals; + RevEngUtils::distToSurf(group_points_.begin(), group_points_.end(), + cone, tol, maxd, avd, num2, num2_2, inpt, outpt, + parvals, dist_ang, angtol); +#ifdef DEBUG_EXTRACT + std::ofstream ofd("in_out_cone.g2"); + ofd << "400 1 0 4 155 50 50 255" << std::endl; + ofd << inpt.size() << std::endl; + for (size_t kr=0; kr<inpt.size(); ++kr) + ofd << inpt[kr]->getPoint() << std::endl; + ofd << "400 1 0 4 50 155 50 255" << std::endl; + ofd << outpt.size() << std::endl; + for (size_t kr=0; kr<outpt.size(); ++kr) + ofd << outpt[kr]->getPoint() << std::endl; +#endif + + if (inpt.size() > group_points_.size()/2 && (int)inpt.size() > min_nmb) + { + Point apex2; + shared_ptr<Cone> cone_in = computeCone(inpt, apex2); + vector<RevEngPoint*> inpt_in, outpt_in; //, inpt2, outpt2; + vector<pair<double, double> > dist_ang_in; + vector<double> parvals_in; + double maxd_in, avd_in; + int num2_in, num2_in2; + RevEngUtils::distToSurf(group_points_.begin(), group_points_.end(), + cone_in, tol, maxd_in, avd_in, num2_in, num2_in2, + inpt_in, outpt_in, parvals_in, dist_ang_in, angtol); + +#ifdef DEBUG_EXTRACT + std::ofstream ofd2("in_out_cone2.g2"); + ofd2 << "400 1 0 4 155 50 50 255" << std::endl; + ofd2 << inpt_in.size() << std::endl; + for (size_t kr=0; kr<inpt_in.size(); ++kr) + ofd2 << inpt_in[kr]->getPoint() << std::endl; + ofd2 << "400 1 0 4 50 155 50 255" << std::endl; + ofd2 << outpt_in.size() << std::endl; + for (size_t kr=0; kr<outpt_in.size(); ++kr) + ofd2 << outpt_in[kr]->getPoint() << std::endl; +#endif + + if (num2_in > num2 || avd_in < avd) + { + std::swap(cone, cone_in); + std::swap(num2, num2_in); + std::swap(num2_2, num2_in2); + std::swap(avd, avd_in); + std::swap(maxd, maxd_in); + std::swap(parvals, parvals_in); + std::swap(dist_ang, dist_ang_in); + std::swap(apex, apex2); + // std::cout << "Cone swap" << std::endl; + // std::cout << group_points_.size() << " " << num2_in; + // std::cout << " " << num2 << " " << avd_in << " " << avd; + // std::cout << " " << maxd_in << " " << maxd << std::endl; + } + } + + //int num = (int)group_points_.size(); + double maxd_init, avd_init; + int num_init, num_init2; + getAccuracy(maxd_init, avd_init, num_init, num_init2); + int sf_flag = defineSfFlag(0, tol, num2, num2_2, + avd, true); + double cone_ang = cone->getConeAngle(); + if (0.5*M_PI-fabs(cone_ang) > minang && (!bbox_.containsPoint(apex, tol)) && + sf_flag < ACCURACY_POOR) + { + bool OK = true; + if (associated_sf_.size() > 0) + { + // Check with current approximating surface + double acc_fac1 = 1.25; + double acc_fac2 = 0.75; + if (surfflag_ == ACCURACY_OK && sf_flag > surfflag_) + OK = false; + else if (prefer_elementary == ALWAYS_ELEM) + OK = false; + else if (prefer_elementary == PREFER_ELEM && + ((double)num2 < acc_fac1*num_init || + avd > acc_fac2*avd_init)) + OK = false; + else if (prefer_elementary == BEST_ACCURACY && + (num2 < num_init || avd > avd_init)) + OK = false; + if (sf_flag == ACCURACY_OK && surfflag_ > ACCURACY_OK) + OK = true; + } + + if (OK) + { + found = true; + for (size_t kh=0; kh<group_points_.size(); ++kh) + { + group_points_[kh]->setPar(Vector2D(parvals[2*kh],parvals[2*kh+1])); + group_points_[kh]->setSurfaceDist(dist_ang[kh].first, dist_ang[kh].second); + } + setAccuracy(maxd, avd, num2, num2_2); +#ifdef DEBUG + std::cout << "Cone. N1: " << num << ", N2: " << num2 << ", max: " << maxd << ", av: " << avd << std::endl; +#endif + shared_ptr<HedgeSurface> hedge(new HedgeSurface(cone, this)); + for (size_t kh=0; kh<associated_sf_.size(); ++kh) + prevsfs.push_back(associated_sf_[kh]); + setHedge(hedge.get()); + hedgesfs.push_back(hedge); + setSurfaceFlag(sf_flag); + } + } + if (!basesf_.get() || + (num2 >= num_in_base_ && avd < avdist_base_)) + setBaseSf(cone, maxd, avd, num2, num2_2); + + return found; +} + + +//=========================================================================== +shared_ptr<Cone> RevEngRegion::computeCone(vector<RevEngPoint*>& points, Point& apex) +//=========================================================================== +{ + Point low = bbox_.low(); + Point high = bbox_.high(); + + Point mid(0.0, 0.0, 0.0); + double wgt = 1.0/(double)points.size(); + for (size_t kr=0; kr<points.size(); ++kr) + { + Vector3D xyz = points[kr]->getPoint(); + Point pnt(xyz[0], xyz[1], xyz[2]); + mid += wgt*pnt; + } + Point axis; + Point Cx; + Point Cy; + vector<pair<vector<RevEngPoint*>::iterator, + vector<RevEngPoint*>::iterator> > group; + group.push_back(std::make_pair(points.begin(), points.end())); + RevEngUtils::coneAxis(group, axis, Cx, Cy); + + //Point apex; + double phi; + RevEngUtils::coneApex(group, axis, apex, phi); + + vector<Point> rotated; + RevEngUtils::rotateToPlane(group, Cx, axis, apex, rotated); +#ifdef DEBUG_EXTRACT + double len = low.dist(high); + std::ofstream of("rotated_pts_cone.g2"); + of << "400 1 0 4 255 0 0 255" << std::endl; + of << rotated.size() << std::endl; + for (size_t kr=0; kr<rotated.size(); ++kr) + of << rotated[kr] << std::endl; + of << "410 1 0 4 0 0 255 255" << std::endl; + of << "1" << std::endl; + of << apex-0.5*len*axis << " " << apex+0.5*len*axis << std::endl; + of << "410 1 0 4 0 255 0 255" << std::endl; + of << "1" << std::endl; + of << apex-0.5*len*Cx << " " << apex+0.5*len*Cx << std::endl; +#endif + + Point pos0 = apex + ((mid - apex)*axis)*axis; + double dd = apex.dist(pos0); + double rad0 = dd*tan(phi); + shared_ptr<Cone> cone(new Cone(fabs(rad0), pos0, axis, Cx, phi)); + //cone->setParamBoundsV(-0.2*len, 0.2*len); + + shared_ptr<Circle> circ(new Circle(rad0, pos0, axis, Cx)); + vector<Point> projected; + double maxdp, avdp; + RevEngUtils::projectToPlane(group, axis, pos0, projected, maxdp, avdp); +#ifdef DEBUG_EXTRACT + std::ofstream ofp3("projected_pts_cone.g2"); + ofp3 << "400 1 0 4 255 0 0 255" << std::endl; + ofp3 << projected.size() << std::endl; + for (size_t kr=0; kr<projected.size(); ++kr) + ofp3 << projected[kr] << std::endl; + circ->writeStandardHeader(ofp3); + circ->write(ofp3); +#endif + + return cone; +} + +//=========================================================================== +bool RevEngRegion::adjacentToCylinder(Point mainaxis[3], + double tol, int min_pt, int min_pt_reg, + double angtol, int prefer_elementary, + vector<shared_ptr<HedgeSurface> >& hedgesfs, + vector<HedgeSurface*>& prevsfs, + vector<vector<RevEngPoint*> >& out_groups) +//=========================================================================== +{ + vector<pair<shared_ptr<ElementarySurface>, RevEngRegion*> > adj_elem, adj_elem_base; + getAdjacentElemInfo(adj_elem, adj_elem_base); + + // Check for one and only one cylinder axis + Point pos, axis; + size_t cyl_ix; + for (size_t ki=0; ki<adj_elem.size(); ++ki) + { + if (adj_elem[ki].first->instanceType() == Class_Cylinder) + { + Point loc = adj_elem[ki].first->location(); + Point dir = adj_elem[ki].first->direction(); + if (pos.dimension() == 0) + { + pos = loc; + axis = dir; + cyl_ix = ki; + } + else + { + // Check compatibility + double ang = axis.angle(dir); + ang = std::min(ang, M_PI-ang); + if (ang > angtol) + return false; + + Point axis_pt = pos + ((loc - pos)*axis)*axis; + double dist = loc.dist(axis_pt); + if (dist > tol) + return false; + } + } + } + if (pos.dimension() == 0) + return false; // No adjacent cylinder + + double min_ang = M_PI; + int ix = -1; + for (int ka=0; ka<3; ++ka) + { + double ang = mainaxis[ka].angle(axis); + ang = std::min(ang, M_PI-ang); + if (ang < min_ang) + { + min_ang = ang; + ix = ka; + } + } + + if (ix < 0) + return false; // Should not happen + + Point Cx = mainaxis[(ix+1)%3]; + Point Cy = axis.cross(Cx); + Cy.normalize(); + Cx = Cy.cross(axis); + Cx.normalize(); + + vector<Point> rotated; + vector<pair<vector<RevEngPoint*>::iterator, + vector<RevEngPoint*>::iterator> > group; + group.push_back(std::make_pair(group_points_.begin(), group_points_.end())); + RevEngUtils::rotateToPlane(group, Cy, axis, pos, rotated); + double len = bbox_.low().dist(bbox_.high()); + +#ifdef DEBUG_CYL + std::ofstream of("rotated_pts.g2"); + of << "400 1 0 4 255 0 0 255" << std::endl; + of << rotated.size() << std::endl; + for (size_t kr=0; kr<rotated.size(); ++kr) + of << rotated[kr] << std::endl; + of << "410 1 0 4 0 0 255 255" << std::endl; + of << "1" << std::endl; + of << pos-0.5*len*axis << " " << pos+0.5*len*axis << std::endl; + of << "410 1 0 4 0 255 0 255" << std::endl; + of << "1" << std::endl; + of << pos-0.5*len*Cy << " " << pos+0.5*len*Cy << std::endl; +#endif + + // Approximate rotated points with a circle + Point centre; + double radius; + RevEngUtils::computeCircPosRadius(rotated, Cx, Cy, axis, centre, radius); + shared_ptr<Circle> circ(new Circle(radius, centre, Cx, Cy)); +#ifdef DEBUG_CYL + circ->writeStandardHeader(of); + circ->write(of); +#endif + + // Check accuracy + bool found = false; + double maxd, avd; + int num_in; + RevEngUtils::distToCurve(rotated, circ, tol, maxd, avd, num_in); + if (accuracyOK(min_pt, tol, num_in, avd)) + { + // A surface can be fitted. Check if it is a torus or a sphere + Point axis_pt = pos + ((centre - pos)*axis)*axis; + double dist = centre.dist(axis_pt); + shared_ptr<ElementarySurface> surf; + if (dist < tol) + // Sphere + surf = shared_ptr<ElementarySurface>(new Sphere(radius, centre, + axis, Cx)); + else + // Torus + surf = shared_ptr<ElementarySurface>(new Torus(dist, radius, + axis_pt, axis, Cx)); + +#ifdef DEBUG_CYL + std::ofstream of2("rot_sf.g2"); + surf->writeStandardHeader(of2); + surf->write(of2); + adj_elem[cyl_ix].first->writeStandardHeader(of2); + adj_elem[cyl_ix].first->write(of2); +#endif + // Check accuracy of surface + vector<RevEngPoint*> inpt, outpt; + vector<pair<double, double> > dist_ang; + double maxd, avd; + int num_in, num2_in; + vector<double> parvals; + RevEngUtils::distToSurf(group_points_.begin(), group_points_.end(), + surf, tol, maxd, avd, num_in, num2_in, + inpt, outpt, parvals, dist_ang, + angtol); +#ifdef DEBUG_CYL + std::ofstream ofd2("in_out_elem.g2"); + ofd2 << "400 1 0 4 155 50 50 255" << std::endl; + ofd2 << inpt.size() << std::endl; + for (size_t kr=0; kr<inpt.size(); ++kr) + ofd2 << inpt[kr]->getPoint() << std::endl; + ofd2 << "400 1 0 4 50 155 50 255" << std::endl; + ofd2 << outpt.size() << std::endl; + for (size_t kr=0; kr<outpt.size(); ++kr) + ofd2 << outpt[kr]->getPoint() << std::endl; +#endif + + int sf_flag = defineSfFlag(0, tol, num_in, num2_in, + avd, false); + if (sf_flag < ACCURACY_POOR) + { + for (size_t kh=0; kh<group_points_.size(); ++kh) + { + group_points_[kh]->setPar(Vector2D(parvals[2*kh],parvals[2*kh+1])); + group_points_[kh]->setSurfaceDist(dist_ang[kh].first, dist_ang[kh].second); + } + setAccuracy(maxd, avd, num_in, num2_in); + shared_ptr<HedgeSurface> hedge(new HedgeSurface(surf, this)); + setHedge(hedge.get()); + hedgesfs.push_back(hedge); + setSurfaceFlag(sf_flag); + found = true; + } + + if (!basesf_.get() || + (num2_in >= num_in_base_ && avd < avdist_base_)) + setBaseSf(surf, maxd, avd, num_in, num2_in); + } + return found; +} + + + +//=========================================================================== +bool RevEngRegion::contextCylinder(Point mainaxis[3], + double tol, int min_pt, int min_pt_reg, + double angtol, int prefer_elementary, + vector<shared_ptr<HedgeSurface> >& hedgesfs, + vector<HedgeSurface*>& prevsfs, + vector<vector<RevEngPoint*> >& out_groups) +//=========================================================================== +{ + int min_nmb = 20; + if ((int)group_points_.size() < min_nmb) + return false; + + vector<pair<shared_ptr<ElementarySurface>, RevEngRegion*> > adj_elem, adj_elem_base; + getAdjacentElemInfo(adj_elem, adj_elem_base); + + return contextCylinder(mainaxis, tol, min_pt, min_pt_reg, angtol, + prefer_elementary, adj_elem, hedgesfs, prevsfs, + out_groups); +} + + +//=========================================================================== +bool RevEngRegion::contextCylinder(Point mainaxis[3], + double tol, int min_pt, int min_pt_reg, + double angtol, int prefer_elementary, + vector<pair<shared_ptr<ElementarySurface>, RevEngRegion*> >& adj_elem, + vector<shared_ptr<HedgeSurface> >& hedgesfs, + vector<HedgeSurface*>& prevsfs, + vector<vector<RevEngPoint*> >& out_groups, + int mode) +//=========================================================================== +{ + int min_nmb = 20; + if ((int)group_points_.size() < min_nmb) + return false; + + double angtol2 = 0.1; + Point pos, axis, Cx; + double rad; + vector<pair<shared_ptr<ElementarySurface>, RevEngRegion*> > adj_planar; + vector<RevEngPoint*> cyl_pts; + bool foundaxis = analyseCylinderContext(adj_elem, tol, angtol2, mainaxis, + mode, adj_planar, pos, axis, Cx, + rad, cyl_pts); + if (!foundaxis) + return false; + + shared_ptr<Cylinder> cyl(new Cylinder(rad, pos, axis, Cx)); + +#ifdef DEBUG_CYLCONTEXT + std::ofstream of("context_cyl.g2"); + cyl->writeStandardHeader(of); + cyl->write(of); +#endif + + // // Fetch remaining points + // vector<RevEngPoint*> remaining; + // getRemainingPoints(cyl_pts, remaining); + + // Move points as appropriate + // First check accuracy with respect to cylinder + vector<RevEngPoint*> inpt, outpt; + vector<pair<double, double> > dist_ang; + double maxd, avd; + int num_in, num2_in; + vector<double> parvals; + RevEngUtils::distToSurf(cyl_pts.begin(), cyl_pts.end(), + cyl, tol, maxd, avd, num_in, num2_in, + inpt, outpt, parvals, dist_ang, + angtol); + int sf_flag_cyl = defineSfFlag((int)cyl_pts.size(), 0, tol, num_in, num2_in, + avd, true); + if (sf_flag_cyl >= ACCURACY_POOR) + return false; // Not a good subset + + // Check if parts of this regions represents a likely cylinder + if (hasSurface()) + { + double fac = 1.5; + if (surfflag_ < sf_flag_cyl || avdist_ < fac*avd || + (avdist_ <= tol && avd > tol)) + return false; // Not an improvement + } + + double cyl_lim = 0.3; + if (num2_in < (int)(cyl_lim*(double)group_points_.size())) + return false; + + // Extract points from cylinder + vector<vector<RevEngPoint*> > planar(adj_planar.size()); + vector<RevEngPoint*> remaining; + vector<Point> norm(adj_planar.size()); + vector<Point> loc(adj_planar.size()); + for (size_t ki=0; ki<adj_planar.size(); ++ki) + { + norm[ki] = adj_planar[ki].first->direction(); + Point avnorm = adj_planar[ki].second->getMeanNormal(); + if (norm[ki]*avnorm < 0.0) + norm[ki] *= -1; + loc[ki] = adj_planar[ki].first->location(); + } + + double cyl_dom[4]; // Cylinder domain + cyl_dom[0] = cyl_dom[2] = std::numeric_limits<double>::max(); + cyl_dom[1] = cyl_dom[3] = std::numeric_limits<double>::lowest(); + double ang_fac = 1.1; + double pi4 = 0.25*M_PI; + vector<double> ptdist(adj_planar.size()); + vector<double> ptang(adj_planar.size()); + for (size_t ki=0; ki<group_points_.size(); ++ki) + { + Vector3D xyz = group_points_[ki]->getPoint(); + Point ptpos(xyz[0], xyz[1], xyz[2]); + Point ptnorm = group_points_[ki]->getLocFuncNormal(); + size_t kj; + for (kj=0; kj<ptdist.size(); ++kj) + { + ptdist[kj] = fabs((ptpos-loc[kj])*norm[kj]); + ptang[kj] = norm[kj].angle(ptnorm); + ptang[kj] = std::min(ptang[kj], M_PI-ptang[kj]); + } + double dist3 = dist_ang[ki].first; + Point axis_pt = pos + ((ptpos - pos)*axis)*axis; + double dist4 = ptpos.dist(axis_pt); + double ang3 = dist_ang[ki].second; + for (kj=0; kj<ptdist.size(); ++kj) + { + if (ptdist[kj] < dist3 && ptang[kj] < ang_fac*ang3 && + (dist4 >= rad || axis.angle(norm[kj]) > pi4)) + { + planar[kj].push_back(group_points_[ki]); + break; + } + } + if (kj == ptdist.size()) + { + remaining.push_back(group_points_[ki]); + cyl_dom[0] = std::min(cyl_dom[0], parvals[2*ki]); + cyl_dom[1] = std::max(cyl_dom[1], parvals[2*ki]); + cyl_dom[2] = std::min(cyl_dom[2], parvals[2*ki+1]); + cyl_dom[3] = std::max(cyl_dom[3], parvals[2*ki+1]); + } + } + + // Planes to cylinder + double eps = 1.0e-2; + vector<vector<RevEngPoint*> > plane2cyl(adj_planar.size()); + for (size_t ki=0; ki<adj_planar.size(); ++ki) + { + for (auto it=adj_planar[ki].second->pointsBegin(); + it!=adj_planar[ki].second->pointsEnd(); ++it) + { + Vector3D xyz = (*it)->getPoint(); + Point ptpos(xyz[0], xyz[1], xyz[2]); + Point ptnorm = (*it)->getLocFuncNormal(); + double dist1 = (*it)->getSurfaceDist(); + double ang1 = norm[ki].angle(ptnorm); + ang1 = std::min(ang1, M_PI-ang1); + Point vec = ptpos - pos; + double dist2 = (vec - (vec*axis)*vec).length(); + dist2 = fabs(dist2 - rad); + //double dist2 = fabs((ptpos - pos)*axis); + if (dist2 < dist1) + { + double upar, vpar, tdist; + Point close; + cyl->closestPoint(ptpos, upar, vpar, close, tdist, eps); + Point cnorm; + cyl->normal(cnorm, upar, vpar); + double ang2 = cnorm.angle(ptnorm); + if (ang2 <= angtol2 && vpar >= cyl_dom[2] && vpar <= cyl_dom[3]) + plane2cyl[ki].push_back(*it); + } + } + } + +#ifdef DEBUG_CYLCONTEXT + std::ofstream of1("cyl2plane.g2"); + for (size_t ki=0; ki<planar.size(); ++ki) + if (planar[ki].size() > 0) + { + of1 << "400 1 0 0" << std::endl; + of1 << planar[ki].size() << std::endl; + for (size_t kj=0; kj<planar[ki].size(); ++kj) + of1 << planar[ki][kj]->getPoint() << std::endl; + } + + std::ofstream of2("plane2cyl.g2"); + for (size_t ki=0; ki<plane2cyl.size(); ++ki) + if (plane2cyl[ki].size() > 0) + { + of2 << "400 1 0 0" << std::endl; + of2 << plane2cyl[ki].size() << std::endl; + for (size_t kj=0; kj<plane2cyl[ki].size(); ++kj) + of2 << plane2cyl[ki][kj]->getPoint() << std::endl; + } +#endif + + // Recompute accuracy + vector<RevEngPoint*> inpt2, outpt2; + vector<pair<double, double> > dist_ang2; + double maxd2, avd2; + int num_in2, num2_in2; + vector<double> parvals2; + RevEngUtils::distToSurf(remaining.begin(), remaining.end(), + cyl, tol, maxd2, avd2, num_in2, num2_in2, + inpt2, outpt2, parvals2, dist_ang2, + angtol); + + if (num2_in2 > min_pt && num2_in2 > (int)remaining.size()/2) + { + // Check for deviant points at the boundary + shared_ptr<RevEngRegion> reg(new RevEngRegion(classification_type_, + edge_class_type_, remaining)); + + vector<RevEngPoint*> dist_points; + reg->identifyDistPoints(dist_ang2, tol, maxd2, avd2, dist_points); + if (dist_points.size() > 0) + { + reg->extractSpesPoints(dist_points, out_groups, true); + + vector<RevEngPoint*> remaining2; + remaining2 = reg->getPoints(); + for (size_t ki=0; ki<remaining2.size(); ++ki) + remaining2[ki]->setRegion(this); + + std::swap(remaining, remaining2); + } + else + { + for (size_t ki=0; ki<remaining.size(); ++ki) + remaining[ki]->setRegion(this); + } + } + + for (size_t ki=0; ki<plane2cyl.size(); ++ki) + if (plane2cyl[ki].size() > 0) + { + for (size_t kj=0; kj<plane2cyl[ki].size(); ++kj) + plane2cyl[ki][kj]->setRegion(this); + remaining.insert(remaining.end(), plane2cyl[ki].begin(), plane2cyl[ki].end()); // Is now double + } + + // Recompute accuracy + Point x_axis, y_axis, z_axis; + cyl->getCoordinateAxes(x_axis, y_axis, z_axis); + Point pos2; + double rad2; + vector<pair<vector<RevEngPoint*>::iterator, + vector<RevEngPoint*>::iterator> > points; + points.push_back(make_pair(remaining.begin(), remaining.end())); + Point low = bbox_.low(); + Point high = bbox_.high(); + RevEngUtils::computeCylPosRadius(points, low, high, z_axis, + x_axis, y_axis, pos2, rad2); + shared_ptr<Cylinder> cyl2(new Cylinder(rad2, pos2, z_axis, x_axis)); +#ifdef DEBUG_CYLCONTEXT + std::ofstream of3("context_cyl2.g2"); + cyl2->writeStandardHeader(of3); + cyl2->write(of3); +#endif + + vector<RevEngPoint*> inpt3, outpt3; + vector<pair<double, double> > dist_ang3; + double maxd3, avd3; + int num_in3, num2_in3; + vector<double> parvals3; + RevEngUtils::distToSurf(remaining.begin(), remaining.end(), + cyl, tol, maxd3, avd3, num_in3, num2_in3, + inpt3, outpt3, parvals3, dist_ang3, + angtol); + + vector<RevEngPoint*> inpt4, outpt4; + vector<pair<double, double> > dist_ang4; + double maxd4, avd4; + int num_in4, num2_in4; + vector<double> parvals4; + RevEngUtils::distToSurf(remaining.begin(), remaining.end(), + cyl2, tol, maxd4, avd4, num_in4, num2_in4, + inpt4, outpt4, parvals4, dist_ang4, + angtol); + if (avd4 < avd3 && num_in4+num2_in4 < num_in3+num2_in3) + { + std::swap(maxd4, maxd3); + std::swap(avd4, avd3); + std::swap(num_in4, num_in3); + std::swap(num2_in4, num2_in3); + std::swap(parvals4, parvals3); + std::swap(dist_ang4, dist_ang3); + std::swap(inpt4, inpt3); + std::swap(outpt4, outpt3); + } + + // Move points +#ifdef DEBUG_CYLCONTEXT + std::ofstream of4("cyl_pts.g2"); + writeRegionPoints(of4); +#endif + + int sf_flag = defineSfFlag((int)remaining.size(), 0, tol, num_in3, num2_in3, avd3, true); + bool OKsurf = (sf_flag < ACCURACY_POOR); + bool hasSurf = (associated_sf_.size() > 0); + if (hasSurf) + { + double acc_fac = 1.5; + double maxd_init, avd_init; + int num_init, num_init2; + getAccuracy(maxd_init, avd_init, num_init, num_init2); + int sfcode; + int sftype = associated_sf_[0]->instanceType(sfcode); + double ang = (sftype == Class_Plane) ? + normalcone_.angle() : M_PI; + double ang_lim = 0.1*M_PI; + + // Check with current approximating surface + if (surfflag_ == ACCURACY_OK && sf_flag > surfflag_) + OKsurf = false; + else if (num_init > num_in3 && num_init2 > num2_in3 && avd_init < avd3) + OKsurf = false; + else if (prefer_elementary == ALWAYS_ELEM || + prefer_elementary == PREFER_ELEM) + { + if (!(ang > ang_lim && (num_in3 < num_init || + (avd3 < avd_init && + num_in3 < acc_fac*num_init)))) + OKsurf = false; + } + else + { + if (!(num_in3 < num_init || + (avd3 < avd_init && num_in3 < acc_fac*num_init))) + OKsurf = true; + } + if (sf_flag == ACCURACY_OK && surfflag_ > ACCURACY_OK) + OKsurf = true; + } + + + if (OKsurf || hasSurf == false) + { + std::swap(group_points_, remaining); + for (size_t ki=0; ki<plane2cyl.size(); ++ki) + if (plane2cyl[ki].size() > 0) + { + for (size_t kj=0; kj<plane2cyl[ki].size(); ++kj) + { + adj_planar[ki].second->removePoint(plane2cyl[ki][kj]); + plane2cyl[ki][kj]->setRegion(this); + } + adj_planar[ki].second->updateInfo(); + } + } + + + if (OKsurf) + { + for (size_t ki=0; ki<group_points_.size(); ++ki) + { + group_points_[ki]->setPar(Vector2D(parvals3[2*ki],parvals3[2*ki+1])); + group_points_[ki]->setSurfaceDist(dist_ang3[ki].first, dist_ang3[ki].second); + } + setAccuracy(maxd3, avd3, num_in3, num2_in3); + shared_ptr<HedgeSurface> hedge(new HedgeSurface(cyl, this)); + setHedge(hedge.get()); + hedgesfs.push_back(hedge); + setSurfaceFlag(sf_flag); + } + + if (OKsurf || hasSurf == false) + { + for (size_t kj=0; kj<planar.size(); ++kj) + { + if (planar[kj].size() > 0) + { + // Parameterize + vector<RevEngPoint*> inpt4, outpt4; + vector<pair<double, double> > dist_ang4; + double maxd4, avd4; + int num_in4, num2_in4; + vector<double> parvals4; + RevEngUtils::distToSurf(planar[kj].begin(), planar[kj].end(), + adj_planar[kj].first, tol, maxd4, avd4, + num_in4, num2_in4, inpt4, outpt4, parvals4, + dist_ang4, angtol); + for (size_t ki=0; ki<planar[kj].size(); ++ki) + { + planar[kj][ki]->setPar(Vector2D(parvals4[2*ki],parvals4[2*ki+1])); + planar[kj][ki]->setSurfaceDist(dist_ang4[ki].first, dist_ang4[ki].second); + planar[kj][ki]->setRegion(adj_planar[kj].second); + adj_planar[kj].second->addPoint(planar[kj][ki]); + } + adj_planar[kj].second->updateInfo(); + + double maxd5, avd5; + int num_5, num2_5; + adj_planar[kj].second->getAccuracy(maxd5, avd5, num_5, num2_5); + int sf_flag2 = + adj_planar[kj].second->defineSfFlag(0, tol, num_5, + num2_5, avd5, false); + + adj_planar[kj].second->setSurfaceFlag(sf_flag2); + } + } + + + for (size_t ki=0; ki<adj_planar.size(); ++ki) + { + int num = adj_planar[ki].second->numPoints(); + for (int ka=0; ka<num; ++ka) + { + RevEngRegion *reg = adj_planar[ki].second->getPoint(ka)->region(); + if (reg != adj_planar[ki].second) + std::cout << "contextCylinder. Region mismatch " << reg << " " << adj_planar[ki].second << std::endl; + } + } + + // Ensure that the point group is connected + vector<vector<RevEngPoint*> > added_groups; + splitRegion(added_groups); + if (added_groups.size() > 0) + out_groups.insert(out_groups.end(), added_groups.begin(), added_groups.end()); + + updateInfo(tol, angtol); + } + else + { + for (size_t ki=0; ki<plane2cyl.size(); ++ki) + if (plane2cyl[ki].size() > 0) + { + for (size_t kj=0; kj<plane2cyl[ki].size(); ++kj) + { + plane2cyl[ki][kj]->setRegion(adj_planar[ki].second); + } + } + for (size_t ki=0; ki<out_groups.size(); ++ki) + for (size_t kj=0; kj<out_groups[ki].size(); ++kj) + out_groups[ki][kj]->setRegion(this); + out_groups.clear(); + } + + return OKsurf; + //return false; +} + +//=========================================================================== +bool RevEngRegion::contextTorus(Point mainaxis[3], + double tol, int min_pt, int min_pt_reg, + double angtol, int prefer_elementary, + vector<shared_ptr<HedgeSurface> >& hedgesfs, + vector<HedgeSurface*>& prevsfs, + vector<vector<RevEngPoint*> >& out_groups) +//=========================================================================== +{ + //bool found = false; + int min_nmb = 20; + if ((int)group_points_.size() < min_nmb) + return false; + + + vector<pair<shared_ptr<ElementarySurface>, RevEngRegion*> > adj_elem, adj_elem_base;; + getAdjacentElemInfo(adj_elem, adj_elem_base); + + Point pos, axis, Cx; + vector<size_t> adj_ix; + double R1, R2, R1_tor; + double cyl_dom[4]; + bool outer; + int plane_ix, cyl_ix; + bool analyse_rotated = false; + bool foundaxis = analyseTorusContext(adj_elem, tol, angtol, adj_ix, + plane_ix, cyl_ix, pos, axis, Cx, + R1, R2, cyl_dom, outer, analyse_rotated); + if (!foundaxis) + return false; + + Point low = bbox_.low(); + Point high = bbox_.high(); + double len = low.dist(high); + if (analyse_rotated) + { + vector<Point> rotated0; + vector<pair<vector<RevEngPoint*>::iterator, + vector<RevEngPoint*>::iterator> > group0; + group0.push_back(std::make_pair(group_points_.begin(), group_points_.end())); + RevEngUtils::rotateToPlane(group0, Cx, axis, pos, rotated0); +#ifdef DEBUG_TORUSCONTEXT + std::ofstream of3("rotated_pts_contexttor.g2"); + of3 << "400 1 0 4 255 0 0 255" << std::endl; + of3 << rotated0.size() << std::endl; + for (size_t kr=0; kr<rotated0.size(); ++kr) + of3 << rotated0[kr] << std::endl; + of3 << "410 1 0 4 0 0 255 255" << std::endl; + of3 << "1" << std::endl; + of3 << pos-0.5*len*axis << " " << pos+0.5*len*axis << std::endl; + of3 << "410 1 0 4 0 255 0 255" << std::endl; + of3 << "1" << std::endl; + of3 << pos-0.5*len*Cx << " " << pos+0.5*len*Cx << std::endl; +#endif + } + + double eps = 1.0e-6; + Point pos2 = pos - R2*axis; + Point Cy = axis.cross(Cx); + shared_ptr<Torus> tor0(new Torus(R1, R2, pos2, axis, Cx)); + R1_tor = R1; + +#ifdef DEBUG_TORUSCONTEXT + std::ofstream oft("torus_context.g2"); + tor0->writeStandardHeader(oft); + tor0->write(oft); +#endif + + shared_ptr<ElementarySurface> cyl = adj_elem[cyl_ix].first; + shared_ptr<ElementarySurface> plane = adj_elem[plane_ix].first; + double rad = cyl->radius(0.0, 0.0); + + // Extract the points feasible for a torus adjacent to the + // identified cylinder, and check if they constitute a point cloud + // of sufficiant size + double limit = 1.1*R2; + vector<RevEngPoint*> inside, outside; + for (size_t kr=0; kr<group_points_.size(); ++kr) + { + Vector3D xyz = group_points_[kr]->getPoint(); + Point xyz2(xyz[0], xyz[1], xyz[2]); + Point onaxis = pos + ((xyz2-pos)*axis)*axis; + double dd = xyz2.dist(onaxis); + if (dd >= rad-limit && dd <= rad+limit) + inside.push_back(group_points_[kr]); + else + outside.push_back(group_points_[kr]); + } + + if ((int)inside.size() < min_pt_reg) + return false; + + //#ifdef DEBUG_TORUSCONTEXT + // Check accuracy of inside points with respect to the current + // torus + vector<RevEngPoint*> inpt0, outpt0; + vector<pair<double, double> > dist_ang0; + double maxd0, avd0; + int num_in0, num2_in0; + vector<double> parvals0; + RevEngUtils::distToSurf(inside.begin(), inside.end(), + tor0, tol, maxd0, avd0, num_in0, num2_in0, + inpt0, outpt0, parvals0, dist_ang0, + angtol); + + //#endif + + // Identify points belonging to the adjacent cylinder + // First rotate current point cloud according to the found axis + vector<RevEngPoint*> cyl_pts, remaining; + vector<Point> rotated; + vector<pair<vector<RevEngPoint*>::iterator, + vector<RevEngPoint*>::iterator> > group; + group.push_back(std::make_pair(inside.begin(), inside.end())); + RevEngUtils::rotateToPlane(group, Cx, axis, pos, rotated); + double angtol2 = angtol; + if (adj_elem[cyl_ix].second->getSurfaceFlag() == PROBABLE_HELIX) + angtol2 = 0.5*M_PI; // Cannot expect angular accuracy for a helix + RevEngUtils::extractLinearPoints(inside, rotated, + len, pos, axis, rad, axis, false, + tol, angtol2, dist_ang0, + cyl_pts, true, remaining); + +#ifdef DEBUG_TORUSCONTEXT + std::ofstream of3("rotated_pts_contexttor.g2"); + of3 << "400 1 0 4 255 0 0 255" << std::endl; + of3 << rotated.size() << std::endl; + for (size_t kr=0; kr<rotated.size(); ++kr) + of3 << rotated[kr] << std::endl; + of3 << "410 1 0 4 0 0 255 255" << std::endl; + of3 << "1" << std::endl; + of3 << pos-0.5*len*axis << " " << pos+0.5*len*axis << std::endl; + of3 << "410 1 0 4 0 255 0 255" << std::endl; + of3 << "1" << std::endl; + of3 << pos-0.5*len*Cx << " " << pos+0.5*len*Cx << std::endl; + + std::ofstream ofl("lin_extract1.g2"); + if (cyl_pts.size() > 0) + { + ofl << "400 1 0 4 55 100 100 255" << std::endl; + ofl << cyl_pts.size() << std::endl; + for (size_t kr=0; kr<cyl_pts.size(); ++kr) + ofl << cyl_pts[kr]->getPoint() << std::endl; + } + + if (remaining.size() > 0) + { + ofl << "400 1 0 4 100 100 55 255" << std::endl; + ofl << remaining.size() << std::endl; + for (size_t kr=0; kr<remaining.size(); ++kr) + ofl << remaining[kr]->getPoint() << std::endl; + } + + if (outside.size() > 0) + { + ofl << "400 1 0 4 10 10 10 255" << std::endl; + ofl << outside.size() << std::endl; + for (size_t kr=0; kr<outside.size(); ++kr) + ofl << outside[kr]->getPoint() << std::endl; + } +#endif + + // Recompute torus + double cpdist = R2; + double up, vp, dd; + Point cl; + for (size_t kr=0; kr<cyl_pts.size(); ++kr) + { + Vector3D xyz = cyl_pts[kr]->getPoint(); + Point xyz2(xyz[0], xyz[1], xyz[2]); + adj_elem[plane_ix].first->closestPoint(xyz2, up, vp, cl, dd, eps); + cpdist = std::min(cpdist, dd); + } + Point pos3 = pos - cpdist*axis; + int sgn = (outer) ? -1 : 1; + R1_tor = rad+sgn*cpdist; + shared_ptr<Torus> tor(new Torus(R1_tor, cpdist, pos3, axis, Cx)); + +#ifdef DEBUG_TORUSCONTEXT + tor->writeStandardHeader(oft); + tor->write(oft); +#endif + + // Check accuracy of identified cylinder points with respect to the + // adjacent cylinder + vector<pair<double, double> > dist_ang_cyl; + double maxd_cyl, avd_cyl; + int num_in_cyl, num2_in_cyl; + vector<double> parvals_cyl; + if (cyl_pts.size() > 0) + { + vector<RevEngPoint*> inpt_cyl, outpt_cyl; + RevEngUtils::distToSurf(cyl_pts.begin(), cyl_pts.end(), + cyl, tol, maxd_cyl, avd_cyl, num_in_cyl, num2_in_cyl, + inpt_cyl, outpt_cyl, parvals_cyl, dist_ang_cyl, + angtol); + int sf_flag_cyl = defineSfFlag((int)cyl_pts.size(), 0, tol, num_in_cyl, + num2_in_cyl, avd_cyl, true); + if (sf_flag_cyl >= ACCURACY_POOR) + { + // Something unexpected happened. Return to previous stage + R1_tor = R1; + tor = tor0; + remaining = inside; + cyl_pts.clear(); + } + } + + // Compute torus accuracy + vector<RevEngPoint*> inpt, outpt; + vector<pair<double, double> > dist_ang; + double maxd, avd; + int num_in, num2_in; + vector<double> parvals; + RevEngUtils::distToSurf(remaining.begin(), remaining.end(), + tor, tol, maxd, avd, num_in, num2_in, + inpt, outpt, parvals, dist_ang, + angtol); + + if (hasSurface()) + { + double fac = 1.5; + int sf_flag_tor = defineSfFlag((int)remaining.size(), 0, tol, + num_in, num2_in, avd, false); + if (surfflag_ < sf_flag_tor || avdist_ < fac*avd || + (avdist_ <= tol && avd > tol)) + return false; // Not an improvement + } + + // Check if parts of this regions represents a likely torus + double tor_lim = 0.3; + if (num2_in < (int)(tor_lim*(double)remaining.size())) + { + // Check if a candidate segmentation strategy is found + if (outside.size() > group_points_.size()/10 && + outside.size() > min_pt_reg) + { + shared_ptr<SegmentData> seg_info(new SegmentData(1, pos, axis, + rad-limit, + rad+limit)); + seg_info_.push_back(seg_info); + } + + return false; + } + + // Extract planar points and additional cylindrical points from torus + vector<RevEngPoint*> planar; + vector<RevEngPoint*> remaining2; + Point axis2 = cyl->direction(); + double pihalf = 0.5*M_PI; + double tor_dom[4]; // Torus domain + tor_dom[0] = tor_dom[2] = std::numeric_limits<double>::max(); + tor_dom[1] = tor_dom[3] = std::numeric_limits<double>::lowest(); + for (size_t ki=0; ki<remaining.size(); ++ki) + { + Vector3D xyz = remaining[ki]->getPoint(); + Point ptpos(xyz[0], xyz[1], xyz[2]); + Point norm = remaining[ki]->getLocFuncNormal(); + Point norm2 = remaining[ki]->getTriangNormal(); + double dist = pos.dist(ptpos); + double ang1 = axis.angle(norm); + double ang2 = axis.angle(norm2); + double ang3 = axis2.angle(norm); + double ang4 = axis2.angle(norm2); + if (((dist < R1_tor && outer) || (dist > R1_tor && (!outer))) && + (ang1 <= angtol2 || ang2 <= angtol2)) + planar.push_back(remaining[ki]); + else if (fabs(pihalf-ang3) <= dist_ang[ki].second || + fabs(pihalf-ang4) <= dist_ang[ki].second || + dist_ang[ki].first > tol) + { + double upar, vpar, tdist; + Point close; + cyl->closestPoint(ptpos, upar, vpar, close, tdist, eps); + bool OKcyl = false; + if (tdist <= dist_ang[ki].first && upar >= cyl_dom[0] && + upar <= cyl_dom[1] && vpar >= cyl_dom[2] && vpar <= cyl_dom[3]) + cyl_pts.push_back(remaining[ki]); + else + { + remaining2.push_back(remaining[ki]); + tor_dom[0] = std::min(tor_dom[0], parvals[2*ki]); + tor_dom[1] = std::max(tor_dom[1], parvals[2*ki]); + tor_dom[2] = std::min(tor_dom[2], parvals[2*ki+1]); + tor_dom[3] = std::max(tor_dom[3], parvals[2*ki+1]); + } + } + else + { + remaining2.push_back(remaining[ki]); + tor_dom[0] = std::min(tor_dom[0], parvals[2*ki]); + tor_dom[1] = std::max(tor_dom[1], parvals[2*ki]); + tor_dom[2] = std::min(tor_dom[2], parvals[2*ki+1]); + tor_dom[3] = std::max(tor_dom[3], parvals[2*ki+1]); + } + } + + // Plane to torus + vector<RevEngPoint*> plan2tor; + for (auto it=adj_elem[plane_ix].second->pointsBegin(); + it!=adj_elem[plane_ix].second->pointsEnd(); ++it) + { + Vector3D xyz = (*it)->getPoint(); + Point ptpos(xyz[0], xyz[1], xyz[2]); + Point norm = (*it)->getLocFuncNormal(); + double dist = pos.dist(ptpos); + double ang = axis.angle(norm); + ang = std::min(ang, M_PI-ang); + if ((dist > R1 && outer) || (dist < R1 && (!outer))) + { + double upar, vpar, tdist; + Point close; + tor->closestPoint(ptpos, upar, vpar, close, tdist, eps); + Point tnorm; + tor->normal(tnorm, upar, vpar); + double ang2 = tnorm.angle(norm); + if (tdist < (*it)->getSurfaceDist() && ang2 <= angtol2 && + upar >= tor_dom[0] && upar <= tor_dom[1]) + plan2tor.push_back(*it); + } + } + + // Cylinder to torus + vector<RevEngPoint*> cyl2tor; + for (auto it=adj_elem[cyl_ix].second->pointsBegin(); + it!=adj_elem[cyl_ix].second->pointsEnd(); ++it) + { + Vector3D xyz = (*it)->getPoint(); + Vector2D uv = (*it)->getPar(); + Point ptpos(xyz[0], xyz[1], xyz[2]); + Point norm = (*it)->getLocFuncNormal(); + if (uv[0] < cyl_dom[0] || uv[0] > cyl_dom[1] || + uv[1] < cyl_dom[2] || uv[1] > cyl_dom[3]) + { + double upar, vpar, tdist; + Point close; + tor->closestPoint(ptpos, upar, vpar, close, tdist, eps); + Point tnorm; + tor->normal(tnorm, upar, vpar); + double ang2 = tnorm.angle(norm); + if (tdist < (*it)->getSurfaceDist() && ang2 <= angtol2) + cyl2tor.push_back(*it); + } + } + +#ifdef DEBUG_TORUSCONTEXT + if (planar.size() > 0) + { + std::ofstream ofp("planar_move.g2"); + ofp << "400 1 0 4 255 0 0 255" << std::endl; + ofp << planar.size() << std::endl; + for (size_t kr=0; kr<planar.size(); ++kr) + ofp << planar[kr]->getPoint() << std::endl; + } + + if (plan2tor.size() > 0) + { + std::ofstream oftp("plan_tor_move.g2"); + oftp << "400 1 0 4 0 255 0 255" << std::endl; + oftp << plan2tor.size() << std::endl; + for (size_t kr=0; kr<plan2tor.size(); ++kr) + oftp << plan2tor[kr]->getPoint() << std::endl; + } + + if (cyl_pts.size() > 0) + { + std::ofstream ofc("cyl_move.g2"); + ofc << "400 1 0 4 255 0 0 255" << std::endl; + ofc << cyl_pts.size() << std::endl; + for (size_t kr=0; kr<cyl_pts.size(); ++kr) + ofc << cyl_pts[kr]->getPoint() << std::endl; + } + + if (cyl2tor.size() > 0) + { + std::ofstream oftc("cyl_tor_move.g2"); + oftc << "400 1 0 4 0 255 0 255" << std::endl; + oftc << cyl2tor.size() << std::endl; + for (size_t kr=0; kr<cyl2tor.size(); ++kr) + oftc << cyl2tor[kr]->getPoint() << std::endl; + } +#endif + + // Recompute accuracy + vector<RevEngPoint*> inpt2, outpt2; + vector<pair<double, double> > dist_ang2; + double maxd2, avd2; + int num_in2, num2_in2; + vector<double> parvals2; + RevEngUtils::distToSurf(remaining2.begin(), remaining2.end(), + tor, tol, maxd2, avd2, num_in2, num2_in2, + inpt2, outpt2, parvals2, dist_ang2, + angtol); +#ifdef DEBUG_TORUSCONTEXT + std::ofstream ofd2("in_out_tor_context.g2"); + ofd2 << "400 1 0 4 155 50 50 255" << std::endl; + ofd2 << inpt2.size() << std::endl; + for (size_t kr=0; kr<inpt2.size(); ++kr) + ofd2 << inpt2[kr]->getPoint() << std::endl; + ofd2 << "400 1 0 4 50 155 50 255" << std::endl; + ofd2 << outpt2.size() << std::endl; + for (size_t kr=0; kr<outpt2.size(); ++kr) + ofd2 << outpt2[kr]->getPoint() << std::endl; +#endif + + if (num2_in2 > min_pt && num2_in2 > (int)remaining2.size()/2) + { + // Check for deviant points at the boundary + shared_ptr<RevEngRegion> reg(new RevEngRegion(classification_type_, + edge_class_type_, remaining2)); + + vector<RevEngPoint*> dist_points; + reg->identifyDistPoints(dist_ang2, tol, maxd2, avd2, dist_points); + if (dist_points.size() > 0) + { + reg->extractSpesPoints(dist_points, out_groups, true); + + vector<RevEngPoint*> remaining3; + remaining3 = reg->getPoints(); + for (size_t ki=0; ki<remaining3.size(); ++ki) + remaining3[ki]->setRegion(this); + + std::swap(remaining2, remaining3); + } + else + { + for (size_t ki=0; ki<remaining2.size(); ++ki) + remaining2[ki]->setRegion(this); + } + } + + if (plan2tor.size() > 0) + { + remaining2.insert(remaining2.end(), plan2tor.begin(), plan2tor.end()); + } + + if (cyl2tor.size() > 0) + { + remaining2.insert(remaining2.end(), cyl2tor.begin(), cyl2tor.end()); + } + + // Recompute accuracy + vector<RevEngPoint*> inpt3, outpt3; + vector<pair<double, double> > dist_ang3; + double maxd3, avd3; + int num_in3, num2_in3; + vector<double> parvals3; + RevEngUtils::distToSurf(remaining2.begin(), remaining2.end(), + tor, tol, maxd3, avd3, num_in3, num2_in3, + inpt3, outpt3, parvals3, dist_ang3, + angtol); +#ifdef DEBUG_TORUSCONTEXT + std::ofstream ofd3("in_out_tor_context3.g2"); + ofd3 << "400 1 0 4 155 50 50 255" << std::endl; + ofd3 << inpt3.size() << std::endl; + for (size_t kr=0; kr<inpt3.size(); ++kr) + ofd3 << inpt3[kr]->getPoint() << std::endl; + ofd3 << "400 1 0 4 50 155 50 255" << std::endl; + ofd3 << outpt3.size() << std::endl; + for (size_t kr=0; kr<outpt3.size(); ++kr) + ofd3 << outpt3[kr]->getPoint() << std::endl; +#endif + + // Check if this surface is better than an eventual previous surface. Move points + int sf_flag = defineSfFlag((int)remaining2.size(), 0, tol, num_in3, num2_in3, avd3, false); + bool OKsurf = (sf_flag < ACCURACY_POOR); + bool hasSurf = (associated_sf_.size() > 0); + if (hasSurf) + { + double acc_fac = 1.5; + double maxd_init, avd_init; + int num_init, num_init2; + getAccuracy(maxd_init, avd_init, num_init, num_init2); + + // Check with current approximating surface + if (surfflag_ == ACCURACY_OK && sf_flag > surfflag_) + OKsurf = false; + else if (prefer_elementary == ALWAYS_ELEM || + prefer_elementary == PREFER_ELEM) + { + if ((double)num_init/(double)group_points_.size() > + (double)num_in3/(double)remaining.size() && + (avd_init <= avd3 || num_in3 >= acc_fac*num_init)) + OKsurf = false; + } + else + { + if (!(num_in3 < num_init || + (avd3 < avd_init && num_in3 < acc_fac*num_init))) + OKsurf = true; + } + if (sf_flag == ACCURACY_OK && surfflag_ > ACCURACY_OK) + OKsurf = true; + } + + if (OKsurf || hasSurf == false) + { + std::swap(group_points_, remaining2); + if (plan2tor.size() > 0) + { + for (size_t kj=0; kj<plan2tor.size(); ++kj) + { + adj_elem[plane_ix].second->removePoint(plan2tor[kj]); + plan2tor[kj]->setRegion(this); + } + adj_elem[plane_ix].second->updateInfo(tol, angtol); + } + + if (cyl2tor.size() > 0) + { + for (size_t kj=0; kj<cyl2tor.size(); ++kj) + { + adj_elem[cyl_ix].second->removePoint(cyl2tor[kj]); + cyl2tor[kj]->setRegion(this); + } + adj_elem[cyl_ix].second->updateInfo(tol, angtol); + } + } + + if (OKsurf) + { + for (size_t ki=0; ki<group_points_.size(); ++ki) + { + group_points_[ki]->setPar(Vector2D(parvals3[2*ki],parvals3[2*ki+1])); + group_points_[ki]->setSurfaceDist(dist_ang3[ki].first, dist_ang3[ki].second); + } + setAccuracy(maxd3, avd3, num_in3, num2_in3); + shared_ptr<HedgeSurface> hedge(new HedgeSurface(tor, this)); + setHedge(hedge.get()); + hedgesfs.push_back(hedge); + setSurfaceFlag(sf_flag); + } + if (OKsurf || hasSurf == false) + { + if (planar.size() > 0) + { + // Parameterize + vector<RevEngPoint*> inpt4, outpt4; + vector<pair<double, double> > dist_ang4; + double maxd4, avd4; + int num_in4, num2_in4; + vector<double> parvals4; + RevEngUtils::distToSurf(planar.begin(), planar.end(), + plane, tol, maxd4, avd4, num_in4, num2_in4, + inpt4, outpt4, parvals4, dist_ang4, + angtol); + for (size_t ki=0; ki<planar.size(); ++ki) + { + planar[ki]->setPar(Vector2D(parvals4[2*ki],parvals4[2*ki+1])); + planar[ki]->setSurfaceDist(dist_ang4[ki].first, dist_ang4[ki].second); + adj_elem[plane_ix].second->addPoint(planar[ki]); + } + adj_elem[plane_ix].second->updateInfo(tol, angtol); + + double maxd5, avd5; + int num_in5, num2_in5; + adj_elem[plane_ix].second->getAccuracy(maxd5, avd5, num_in5, num2_in5); + int sf_flag5 = adj_elem[plane_ix].second->defineSfFlag(0, tol, + num_in5, num2_in5, + avd5, false); + adj_elem[plane_ix].second->setSurfaceFlag(sf_flag5); + } + + if (cyl_pts.size() > 0) + { + // Parameterize + vector<RevEngPoint*> inpt4, outpt4; + vector<pair<double, double> > dist_ang4; + double maxd4, avd4; + int num_in4, num2_in4; + vector<double> parvals4; + RevEngUtils::distToSurf(cyl_pts.begin(), cyl_pts.end(), + cyl, tol, maxd4, avd4, num_in4, num2_in4, + inpt4, outpt4, parvals4, dist_ang4, + angtol); + for (size_t ki=0; ki<cyl_pts.size(); ++ki) + { + cyl_pts[ki]->setPar(Vector2D(parvals4[2*ki],parvals4[2*ki+1])); + cyl_pts[ki]->setSurfaceDist(dist_ang4[ki].first, dist_ang4[ki].second); + adj_elem[cyl_ix].second->addPoint(cyl_pts[ki]); + } + adj_elem[cyl_ix].second->updateInfo(tol, angtol); + + double maxd5, avd5; + int num_in5, num2_in5; + adj_elem[cyl_ix].second->getAccuracy(maxd5, avd5, num_in5, num2_in5); + int sf_flag5 = adj_elem[cyl_ix].second->defineSfFlag(0, tol, + num_in5, num2_in5, + avd5, true); + adj_elem[cyl_ix].second->setSurfaceFlag(sf_flag5); + } + + if (numPoints() > 0)//group_points_.size() > 0) + { + // Ensure that the point group is connected + vector<vector<RevEngPoint*> > added_groups; + splitRegion(added_groups); + if (added_groups.size() > 0) + out_groups.insert(out_groups.end(), added_groups.begin(), added_groups.end()); + + updateInfo(tol, angtol); + } + else + { + removeFromAdjacent(); + clearRegionAdjacency(); + } + } + + + if (outside.size() > 0) + { + vector<std::vector<RevEngPoint*> > sep_outside; + std::vector<RevEngPoint*> dummy; + connectedGroups(outside, sep_outside, false, dummy); + out_groups.insert(out_groups.end(), sep_outside.begin(), + sep_outside.end()); + } + + return OKsurf; + + } + +//=========================================================================== +bool RevEngRegion::addPointsToGroup(vector<RevEngPoint*>& points, + double tol, double angtol, bool compute_accuracy) +//=========================================================================== +{ + if (!hasSurface()) + return false; + + shared_ptr<ParamSurface> surf = getSurface(0)->surface(); + + if (compute_accuracy) + { + // Compute accuracy + vector<RevEngPoint*> inpt, outpt; + vector<pair<double, double> > dist_ang; + double maxd, avd; + int num_in, num2_in; + vector<double> parvals; + RevEngUtils::distToSurf(points.begin(), points.end(), + surf, tol, maxd, avd, num_in, num2_in, + inpt, outpt, parvals, dist_ang, + angtol); + + // Update info in points + for (size_t kh=0; kh<points.size(); ++kh) + { + points[kh]->setPar(Vector2D(parvals[2*kh],parvals[2*kh+1])); + points[kh]->setSurfaceDist(dist_ang[kh].first, dist_ang[kh].second); + } + } + for (size_t kh=0; kh<points.size(); ++kh) + points[kh]->setRegion(this); + group_points_.insert(group_points_.end(), points.begin(), points.end()); + updateInfo(tol, angtol); + + bool cyllike = (surf->instanceType() == Class_Cylinder || + surf->instanceType() == Class_Cone); + int sf_flag = defineSfFlag(0, tol, num_inside_, num_inside2_, avdist_, cyllike); + setSurfaceFlag(sf_flag); + + return true; +} + + + +//=========================================================================== +void RevEngRegion::growInDomain(RevEngRegion *adjacent, double tol, + double angtol) +//=========================================================================== +{ + if (!hasSurface()) + return; // No growing is possible + shared_ptr<ParamSurface> surf = getSurface(0)->surface(); + shared_ptr<ParamSurface> surf2; + if (adjacent->hasSurface()) + surf2 = adjacent->getSurface(0)->surface(); + + // Get seed points + vector<RevEngPoint*> pts = adjacent->extractNextToAdjacent(this); + + vector<RevEngPoint*> move; + double eps = 1.0e-6; + for (size_t ki=0; ki<pts.size(); ++ki) + { + pts[ki]->setVisited(); + Vector3D xyz = pts[ki]->getPoint(); + Point pos(xyz[0], xyz[1], xyz[2]); + double upar, vpar, dist; + Point close; + surf->closestPoint(pos, upar, vpar, close, dist, eps); + bool in_domain = surf->inDomain(upar, vpar, eps); + bool at_boundary = surf->onBoundary(upar, vpar, eps); + if (in_domain && (!at_boundary)) + { + bool do_move = true; + if (surf2.get()) + { + Vector2D uv = pts[ki]->getPar(); + if (surf2->inDomain(uv[0], uv[1], eps) && + dist >= pts[ki]->getSurfaceDist()) + do_move = false; + } + if (do_move) + { + move.push_back(pts[ki]); + vector<ftSamplePoint*> next = pts[ki]->getNeighbours(); + for (size_t kj=0; kj<next.size(); ++kj) + { + RevEngPoint *curr = dynamic_cast<RevEngPoint*>(next[kj]); + if (curr->visited()) + continue; + RevEngRegion *adj_reg = curr->region(); + if (adj_reg != adjacent) + continue; + curr->setVisited(); + pts.push_back(curr); + } + } + } + } + + for (size_t ki=0; ki<pts.size(); ++ki) + pts[ki]->unsetVisited(); + + if (move.size() > 0) + { + adjacent->removePoints(move); + adjacent->updateInfo(tol, angtol); + + (void)addPointsToGroup(move, tol, angtol); + } + + +} + +//=========================================================================== +void RevEngRegion::growFromNeighbour(Point mainaxis[3], int min_pt_reg, + vector<RevEngPoint*>& seed, double tol, + double angtol, RevEngRegion *neighbour, + bool do_update) +//=========================================================================== +{ + if (!hasSurface()) + return; // No growing is possible + + bool check_pts = (neighbour->hasSurface()); + + shared_ptr<ParamSurface> surf = getSurface(0)->surface(); + shared_ptr<ElementarySurface> elem = + dynamic_pointer_cast<ElementarySurface,ParamSurface>(surf); + Point axis; + if (elem.get()) + axis = elem->direction(); + double axis_ang = 0.0; + if (surf->instanceType() == Class_Cylinder) + axis_ang = 0.5*M_PI; // To be extended as appropriate + else if (surf->instanceType() == Class_Cone) + { + double cone_ang = ((Cone*)(elem.get()))->getConeAngle(); + axis_ang = 0.5*M_PI - cone_ang; + } + +#ifdef DEBUG_GROWNEIGHBOUR + std::ofstream ofs1("seed1.g2"); + ofs1 << "400 1 0 4 0 200 55 255" << std::endl; + ofs1 << seed.size() << std::endl; + for (size_t ki=0; ki<seed.size(); ++ki) + { + Vector3D xyz = seed[ki]->getPoint(); + ofs1 << xyz << std::endl; + } +#endif + + // Check initial points + double eps = 1.0e-6; + double tol2 = std::max(tol, 0.75*maxdist_); + tol2 = std::min(tol2, 2.0*tol); + double tol3 = 0.5*tol; + //double angtol2 = 0.5*angtol; + vector<RevEngPoint*> next_pts; + double upar, vpar, dist, ang, ang2; + Point close; + double dfac = 1.5; + for (size_t ki=0; ki<seed.size(); ++ki) + { + seed[ki]->setVisited(); + Vector3D xyz = seed[ki]->getPoint(); + Point norm = seed[ki]->getLocFuncNormal(); + Point norm2 = seed[ki]->getTriangNormal(); + surf->closestPoint(Point(xyz[0],xyz[1],xyz[2]), upar, vpar, close, dist, eps); + if (!elem.get()) + surf->normal(axis, upar, vpar); + ang = axis.angle(norm); + ang = fabs(ang-axis_ang); + ang2 = axis.angle(norm2); + ang2 = fabs(ang2-axis_ang); + ang = std::min(std::min(ang, M_PI-ang), std::min(ang2, M_PI-ang2)); + if (dist <= tol3 || (dist <= tol2 && ang <= angtol)) + { + if (check_pts) + { + double init_dist, init_ang; + seed[ki]->getSurfaceDist(init_dist, init_ang); + if ((dist < init_dist && ang < init_ang) || + (dfac*dist < init_dist && ang < dfac*init_ang)) + next_pts.push_back(seed[ki]); + } + else + next_pts.push_back(seed[ki]); + } + } + +#ifdef DEBUG_GROWNEIGHBOUR + std::ofstream of0("curr_region_from.g2"); + neighbour->writeRegionPoints(of0); +#endif + +#ifdef DEBUG_GROWNEIGHBOUR + std::ofstream ofs2("seed2.g2"); + ofs2 << "400 1 0 4 0 200 55 255" << std::endl; + ofs2 << next_pts.size() << std::endl; + for (size_t ki=0; ki<next_pts.size(); ++ki) + { + Vector3D xyz = next_pts[ki]->getPoint(); + ofs2 << xyz << std::endl; + } +#endif + + // Grow + for (size_t ki=0; ki<next_pts.size(); ++ki) + { + vector<ftSamplePoint*> next2 = next_pts[ki]->getNeighbours(); + for (size_t kj=0; kj<next2.size(); ++kj) + { + RevEngPoint *curr = dynamic_cast<RevEngPoint*>(next2[kj]); + if (curr->visited()) + continue; + RevEngRegion *adj_reg = curr->region(); + if (adj_reg != neighbour) + continue; + curr->setVisited(); + Vector3D xyz = curr->getPoint(); + Point norm = curr->getLocFuncNormal(); + Point norm2 = curr->getTriangNormal(); + surf->closestPoint(Point(xyz[0],xyz[1],xyz[2]), upar, vpar, close, dist, eps); + if (!elem.get()) + surf->normal(axis, upar, vpar); + ang = axis.angle(norm); + ang = fabs(ang-axis_ang); + ang2 = axis.angle(norm2); + ang2 = fabs(ang2-axis_ang); + ang = std::min(std::min(ang, M_PI-ang), std::min(ang2, M_PI-ang2)); + if (dist <= tol3 || (dist <= tol2 && ang <= angtol)) + { + if (check_pts) + { + double init_dist, init_ang; + curr->getSurfaceDist(init_dist, init_ang); + if ((dist < init_dist && ang < init_ang) || + (dfac*dist < init_dist && ang < dfac*init_ang)) + next_pts.push_back(curr); + } + else + next_pts.push_back(curr); + } + } + } + for (int ka=0; ka<neighbour->numPoints(); ++ka) + neighbour->getPoint(ka)->unsetVisited(); + + int classtype = surf->instanceType(); + if (classtype == Class_Cylinder) + { + double dom[4]; + Vector2D uv = group_points_[0]->getPar(); + dom[0] = dom[1] = uv[0]; + dom[2] = dom[3] = uv[1]; + double dist, ang, avang; + double fac = 1.0/(double)group_points_.size(); + group_points_[0]->getSurfaceDist(dist, ang); + avang = fac*ang; + for (size_t ki=1; ki<group_points_.size(); ++ki) + { + Vector2D uv = group_points_[ki]->getPar(); + group_points_[ki]->getSurfaceDist(dist, ang); + dom[0] = std::min(dom[0], uv[0]); + dom[1] = std::max(dom[1], uv[0]); + dom[2] = std::min(dom[2], uv[1]); + dom[3] = std::max(dom[3], uv[1]); + avang += fac*ang; + } + + vector<RevEngPoint*> adjpts; + vector<double> par_and_dist; + double avd, ava; + int nn; + getAdjInsideDist(surf, dom, tol, neighbour, avd, ava, nn, adjpts, + par_and_dist); + +#ifdef DEBUG_GROWNEIGHBOUR2 + std::ofstream of2("in_cyl_pts.g2"); + of2 << "400 1 0 4 75 75 75 255" << std::endl; + of2 << adjpts.size() << std::endl; + for (size_t kh=0; kh<adjpts.size(); ++kh) + of2 << adjpts[kh]->getPoint() << std::endl; +#endif + int stop_cyl = 1; + } + + // Move points + for (size_t ki=0; ki<next_pts.size(); ++ki) + { + //addPoint(next_pts[ki]); + neighbour->removePoint(next_pts[ki]); + } + +#ifdef DEBUG_GROWNEIGHBOUR2 + std::ofstream of("updated_region_adj.g2"); + writeRegionInfo(of); +#endif + + // Update this region + bool cyllike = (surf->instanceType() == Class_Cylinder || + surf->instanceType() == Class_Cone); + double frac = 0.1; + int num_init = (int)group_points_.size(); + if (next_pts.size() > 0) + { + // Compute distance + shared_ptr<ParamSurface> surf = getSurface(0)->surface(); + double maxdist, avdist; + int num_in, num2_in; + vector<pair<double, double> > dist_ang; + vector<double> parvals; + vector<RevEngPoint*> inpt, outpt; + RevEngUtils::distToSurf(next_pts.begin(), next_pts.end(), + surf, tol, maxdist, avdist, num_in, num2_in, + inpt, outpt, parvals, dist_ang, angtol); + + for (size_t kh=0; kh<next_pts.size(); ++kh) + { + next_pts[kh]->setPar(Vector2D(parvals[2*kh],parvals[2*kh+1])); + next_pts[kh]->setSurfaceDist(dist_ang[kh].first, dist_ang[kh].second); + next_pts[kh]->setRegion(this); + } + group_points_.insert(group_points_.end(), next_pts.begin(), + next_pts.end()); + updateInfo(tol, angtol); + int sf_flag = defineSfFlag(0, tol, num_inside_, + num_inside2_, avdist_, cyllike); + setSurfaceFlag(sf_flag); + if (do_update && surf_adaption_ == INITIAL && + (double)next_pts.size() > frac*(double)num_init) + checkReplaceSurf(mainaxis, min_pt_reg, tol, angtol); + for (size_t kj=0; kj<rev_edges_.size(); ++kj) + rev_edges_[kj]->increaseExtendCount(); + + neighbour->updateInfo(tol, angtol); + } + + int stop_break = 1; +} + +//=========================================================================== +vector<RevEngRegion*> RevEngRegion::commonAdjacent(RevEngRegion* adj_reg) +//=========================================================================== +{ + vector<RevEngRegion*> common; + for (auto it=adjacent_regions_.begin(); it!=adjacent_regions_.end(); ++it) + { + bool adjacent = (*it)->isAdjacent(adj_reg); + if (adjacent) + common.push_back(*it); + } + return common; +} + +//=========================================================================== +vector<RevEngPoint*> RevEngRegion::extractBdPoints() +//=========================================================================== +{ + vector<RevEngPoint*> result; + for (size_t ki=0; ki<group_points_.size(); ++ki) + { + vector<ftSamplePoint*> next = group_points_[ki]->getNeighbours(); + for (size_t kj=0; kj<next.size(); ++kj) + { + RevEngPoint *curr = dynamic_cast<RevEngPoint*>(next[kj]); + RevEngRegion *adj_reg = curr->region(); + if (adj_reg != this) + { + result.push_back(group_points_[ki]); + break; + } + } + } + return result; +} + +//=========================================================================== +vector<RevEngPoint*> +RevEngRegion::extractBdPoints(vector<RevEngRegion*> regions) +//=========================================================================== +{ + vector<RevEngPoint*> result; + for (size_t ki=0; ki<group_points_.size(); ++ki) + { + vector<ftSamplePoint*> next = group_points_[ki]->getNeighbours(); + for (size_t kj=0; kj<next.size(); ++kj) + { + RevEngPoint *curr = dynamic_cast<RevEngPoint*>(next[kj]); + RevEngRegion *adj_reg = curr->region(); + if (adj_reg != this) + { + size_t kr; + for (kr=0; kr<regions.size(); ++kr) + if (adj_reg == regions[kr]) + break; + + if (kr < regions.size()) + result.push_back(group_points_[ki]); + break; + } + } + } + return result; +} + +//=========================================================================== +vector<RevEngPoint*> RevEngRegion::extractBranchPoints() +//=========================================================================== +{ + vector<RevEngPoint*> result; + for (size_t ki=0; ki<group_points_.size(); ++ki) + { + int num_other = 0; + RevEngRegion *other = 0; + vector<ftSamplePoint*> next = group_points_[ki]->getNeighbours(); + for (size_t kj=0; kj<next.size(); ++kj) + { + RevEngPoint *curr = dynamic_cast<RevEngPoint*>(next[kj]); + RevEngRegion *adj_reg = curr->region(); + if (adj_reg != this) + { + if (num_other == 0) + { + num_other++; + other = adj_reg; + } + else if (adj_reg != other) + { + result.push_back(group_points_[ki]); + break; + } + } + } + } + return result; +} + +//=========================================================================== +vector<RevEngPoint*> RevEngRegion::extractNextToAdjacent(RevEngRegion* reg) +//=========================================================================== +{ + vector<RevEngPoint*> result; + for (size_t ki=0; ki<group_points_.size(); ++ki) + { + vector<ftSamplePoint*> next = group_points_[ki]->getNeighbours(); + for (size_t kj=0; kj<next.size(); ++kj) + { + RevEngPoint *curr = dynamic_cast<RevEngPoint*>(next[kj]); + RevEngRegion *adj_reg = curr->region(); + if (adj_reg == reg) + { + result.push_back(group_points_[ki]); + break; + } + } + } + return result; +} + +struct DistanceInfo +{ + double mind_, maxd_, avd_; + double pmin_, pmax_; + int nmb_; + + DistanceInfo() + { + mind_ = maxd_ = avd_ = pmin_ = pmax_ = 0.0; + nmb_ = 0; + } + + DistanceInfo(double mind, double maxd, double avd, + double pmin, double pmax, int nmb) + { + mind_ = mind; + maxd_ = maxd; + avd_ = avd; + pmin_ = pmin; + pmax_ = pmax; + nmb_ = nmb; + } + + void setInfo(double mind, double maxd, double avd, + double pmin, double pmax, int nmb) + { + mind_ = mind; + maxd_ = maxd; + avd_ = avd; + pmin_ = pmin; + pmax_ = pmax; + nmb_ = nmb; + } +}; + +void RevEngRegion::testBlendGap(vector<shared_ptr<CurveOnSurface> >& cvs, + double tmin, double tmax, double tdel, double width, + vector<pair<double,double> >& not_gap) +{ + double cdel0 = tmax - tmin; + int ncheck = std::max((int)(1.5*cdel0/tdel), 1); + double cdel = cdel0/(double)ncheck; + double cpar; + size_t kr; + vector<size_t> inside; + for (kr=0, cpar=tmin+0.5*cdel; kr<ncheck; ++kr, cpar+=cdel) + { + size_t kh; + for (kh=0; kh<cvs.size(); ++kh) + if (cvs[kh]->startparam() <= cpar && cvs[kh]->endparam() >= cpar) + break; + if (kh >= cvs.size()) + { + std::cout << cvs.size() << " " << kh << std::endl; + } + Point cpt = cvs[kh]->ParamCurve::point(cpar); + double dist; + RevEngPoint* rpt = closestPoint(cpt, dist); + if (dist <= width) + inside.push_back(kr); + else + { + Vector3D xyz = rpt->getPoint(); + Point rpt2(xyz[0], xyz[1], xyz[2]); + double tpar2, dist2; + Point close; + cvs[kh]->closestPoint(rpt2, std::max(cvs[kh]->startparam(),cpar-0.25*cdel), + std::min(cvs[kh]->endparam(),cpar+0.25*cdel), + tpar2, close, dist2); + if (dist2 <= width) + inside.push_back(kr); + } + } + if ((int)inside.size() > ncheck/2) + not_gap.push_back(std::make_pair(tmin, tmax)); + else if (inside.size() > 0) + { + double t1 = tmin + inside[0]*cdel; + double t2 = t1 + cdel; + for (size_t kj=1; kj<inside.size(); ++kj) + { + if (inside[kj] == inside[kj-1]+1) + t2 += cdel; + else + { + not_gap.push_back(std::make_pair(t1, t2)); + t1 = tmin + inside[kj]*cdel; + t2 = t1 + cdel; + } + } + not_gap.push_back(std::make_pair(t1, t2)); + } +} + +//=========================================================================== +void RevEngRegion::estimateBlendDimensions(vector<shared_ptr<CurveOnSurface> >& cvs, + vector<RevEngPoint*>& bd_points, + double tol, double distlim, + vector<pair<double,double> >& t1_t2, + vector<double>& width, int& num_in_lim) +//=========================================================================== +{ + // if (cvs.size() != 1) + // return; // Must consider this later. Will it happen? + + // Parameterize points with respect to the given curve + double eps = 1.0e-9; + vector<double> param(bd_points.size()); + vector<double> distance(bd_points.size()); + + double tmin = cvs[0]->startparam(); + double tmax = cvs[cvs.size()-1]->endparam(); + num_in_lim = 0; + for (size_t ki=0; ki<bd_points.size(); ++ki) + { + double tpar, dist=std::numeric_limits<double>::max();; + Vector3D xyz = bd_points[ki]->getPoint(); + Point pt(xyz[0], xyz[1], xyz[2]); + for (size_t kj=0; kj<cvs.size(); ++kj) + { + double tpar0, dist0; + Point close; + cvs[kj]->closestPoint(pt, cvs[kj]->startparam(), cvs[kj]->endparam(), + tpar0, close, dist0); + if (dist0 < dist) + { + tpar = tpar0; + dist = dist0; + } + } + param[ki] = tpar; + distance[ki] = dist; + tmin = std::min(tmin, tpar); + tmax = std::max(tmax, tpar); + if (dist <= distlim) + num_in_lim++; + } + + if (tmax < tmin+eps) + return; + + // Sort + for (size_t ki=0; ki<bd_points.size(); ++ki) + for (size_t kj=ki+1; kj<bd_points.size(); ++kj) + if (param[kj] < param[ki]) + { + std::swap(bd_points[ki], bd_points[kj]); + std::swap(param[ki], param[kj]); + std::swap(distance[ki], distance[kj]); + } + + // Limit point sequence + size_t first = 0, last = param.size()-1; + eps = std::min(1.0e-9, 1.0e-6*(tmax-tmin)); + for (; first<last; ++first) + if (param[first+1]-param[0] > eps) + break; + for (; last>first; --last) + if (param[param.size()-1]-param[last-1] > eps) + break; + + double mean_out = 0.0; + double min_out = std::numeric_limits<double>::max(); + int nmb_out = 0; + size_t outlim = distance.size()/10; + for (size_t ki=0; ki<std::max(first,outlim); ++ki) + { + min_out = std::min(min_out, distance[ki]); + mean_out += distance[ki]; + nmb_out++; + } + for (size_t ki=std::min(distance.size()-outlim,last+1); + ki<distance.size(); ++ki) + { + min_out = std::min(min_out, distance[ki]); + mean_out += distance[ki]; + nmb_out++; + } + if (nmb_out > 0) + mean_out /= (double)nmb_out; + else + min_out = 10.0*distlim; + + // Find start point for search + double max_dist = 0.0; + double min_dist = std::numeric_limits<double>::max(); + int min_ix = -1; + for (size_t ki=first; ki<=last; ++ki) + { + if (distance[ki] < min_dist) + { + min_dist = distance[ki]; + min_ix = (int)ki; + } + max_dist = std::max(max_dist,distance[ki]); + } + + int ndel = std::max(20, (int)(last-first)/100); + ndel = std::max(1, std::min(ndel, (int)(last-first)/5)); + vector<DistanceInfo> distinfo(ndel); + double dlim = std::max(2.0*distlim, 0.5*(min_out + mean_out)); + double tdel = (tmax-tmin)/(double)ndel; + double tpar; + int ka, kb, ix; + for (ix=0, ka=first, tpar=tmin+tdel; ix<ndel && ka<=(int)last; + ++ix, ka=kb, tpar+=tdel) + { + int nmb = 0; + double maxd=0.0, avd=0.0; + double mind = 2.0*dlim; + for (kb=ka; kb<=(int)last && param[kb]<=tpar; ++kb) + { + if (distance[kb]>dlim) + continue; + ++nmb; + maxd = std::max(maxd, distance[kb]); + mind = std::min(mind, distance[kb]); + avd += distance[kb]; + } + if (nmb > 0) + avd /= (double)nmb; + + distinfo[ix].setInfo(mind, maxd, avd, tpar-tdel, tpar, nmb); + } + + double del = 0.0; + for (size_t ki=0; ki<distinfo.size(); ++ki) + del += (distinfo[ki].avd_ - distinfo[ki].mind_); + del /= (double)(distinfo.size()); + del = std::min(del, mean_out); + + size_t kj, kr; + int pt_out_lim = 5; + double eps2 = 0.01*(mean_out - min_dist); + for (kj=0; kj<distinfo.size(); kj=kr+1) + { + double curr_width = 0.0; + double tmin2 = distinfo[kj].pmin_; + double tmax2 = distinfo[kj].pmax_; + int num_pt = 0; + double min_width = max_dist; + for (kr=kj; kr<distinfo.size(); ++kr) + { + if (distinfo[kr].nmb_ == 0) + break; + if (distinfo[kr].mind_ > distlim) + break; + num_pt += distinfo[kr].nmb_; + + min_width = std::min(min_width, distinfo[kr].mind_); + curr_width = std::max(curr_width, std::min(distinfo[kr].maxd_, + distinfo[kr].mind_+del)); + tmax2 = distinfo[kr].pmax_; + } + if (num_pt > 0 && min_width <= distlim) + { + curr_width = std::min(curr_width, mean_out + 0.1*(max_dist-mean_out)); + curr_width = std::max(curr_width, 0.2*distlim); + curr_width = std::max(curr_width, min_width+eps2); + t1_t2.push_back(std::make_pair(tmin2, tmax2)); + width.push_back(curr_width); + } + } + + // The boundary points may be too sparse. Check if the gaps between + // curve pieces are real + if (t1_t2.size() > 0) + { + size_t nmb = t1_t2.size(); + vector<pair<double,double> > t3_t4; + vector<double> width2; + if (t1_t2[0].first > tmin+eps) + { + vector<pair<double,double> > not_gap; + testBlendGap(cvs, tmin, t1_t2[0].first, tdel, width[0], not_gap); + if (not_gap.size() > 0) + { + t3_t4.insert(t3_t4.end(), not_gap.begin(), not_gap.end()); + for (size_t kh=0; kh<not_gap.size(); ++kh) + width2.push_back(width[0]); + } + } + t3_t4.push_back(t1_t2[0]); + width2.push_back(width[0]); + for (size_t kj=1; kj<t1_t2.size(); ++kj) + { + vector<pair<double,double> > not_gap; + double wdt = 0.5*(width[kj-1]+width[kj]); + testBlendGap(cvs, t1_t2[kj-1].second, t1_t2[kj].first, tdel, wdt, not_gap); + if (not_gap.size() > 0) + { + t3_t4.insert(t3_t4.end(), not_gap.begin(), not_gap.end()); + for (size_t kh=0; kh<not_gap.size(); ++kh) + width2.push_back(wdt); + } + t3_t4.push_back(t1_t2[kj]); + width2.push_back(width[kj]); + } + if (tmax > t1_t2[nmb-1].second) + { + vector<pair<double,double> > not_gap; + testBlendGap(cvs, t1_t2[nmb-1].second, tmax, tdel, width[nmb-1], not_gap); + if (not_gap.size() > 0) + { + t3_t4.insert(t3_t4.end(), not_gap.begin(), not_gap.end()); + for (size_t kh=0; kh<not_gap.size(); ++kh) + width2.push_back(width[nmb-1]); + } + } + if (t3_t4.size() > t1_t2.size()) + { + double ltol = 0.5*tdel; + for (int ka=(int)t3_t4.size()-1; ka>0; --ka) + { + if (t3_t4[ka].first - t3_t4[ka-1].second <= ltol) + { + t3_t4[ka-1].second = t3_t4[ka].second; + width2[ka-1] = 0.5*(width2[ka-1] + width2[ka]); + t3_t4.erase(t3_t4.begin()+ka); + width2.erase(width2.begin()+ka); + } + } + std::swap(t1_t2, t3_t4); + std::swap(width, width2); + } + } + + int stop_break = 1; +} + + +//=========================================================================== +void RevEngRegion::getNearPoints(shared_ptr<CurveOnSurface>& cv, + double& tmin, double& tmax, + double width, double angtol, + vector<RevEngPoint*>& nearpoints) +//=========================================================================== +{ + // if (cvs.size() != 1) + // return; // Must consider this later. Will it happen? + + double pihalf = 0.5*M_PI; + double tmin2 = tmax; + double tmax2 = tmin; + for (size_t ki=0; ki<group_points_.size(); ++ki) + { + double tpar, dist=std::numeric_limits<double>::max(); + Point close; + Vector3D xyz = group_points_[ki]->getPoint(); + Point pt(xyz[0], xyz[1], xyz[2]); + cv->closestPoint(pt, cv->startparam(), cv->endparam(), + tpar, close, dist); + + vector<Point> der(2); + cv->point(der, tpar, 1); + Point vec = pt - close; + double ang = vec.angle(der[1]); + Point norm1 = group_points_[ki]->getLocFuncNormal(); + Point norm2 = group_points_[ki]->getTriangNormal(); + double ang1 = norm1.angle(der[1]); + double ang2 = norm2.angle(der[1]); + ang1 = std::min(ang1, M_PI-ang1); + ang2 = std::min(ang2, M_PI-ang2); + if (tpar > tmin && tpar < tmax && dist <= width && + fabs(pihalf-ang) <= angtol && std::min(ang1,ang2) > angtol) + { + nearpoints.push_back(group_points_[ki]); + tmin2 = std::min(tmin2, tpar); + tmax2 = std::max(tmax2, tpar); + } + } + tmin = tmin2; + tmax = tmax2; +} + +//=========================================================================== +void RevEngRegion::getNearPoints2(vector<RevEngPoint*>& points, + shared_ptr<CurveOnSurface>& cv, + double width, + vector<RevEngPoint*>& nearpoints) +//=========================================================================== +{ + for (size_t ki=0; ki<points.size(); ++ki) + { + Vector3D xyz = points[ki]->getPoint(); + Point pt(xyz[0], xyz[1], xyz[2]); + double tpar, dist; + Point close; + cv->closestPoint(pt, cv->startparam(), cv->endparam(), + tpar, close, dist); + + if (dist <= width) + nearpoints.push_back(points[ki]); + } +} + + + +//=========================================================================== +vector<RevEngPoint*> +RevEngRegion::removeOutOfSurf(vector<RevEngPoint*>& points, + double tol, double angtol, bool outer, + double& min_dist) +//=========================================================================== +{ + vector<RevEngPoint*> result; + double diag = bbox_.low().dist(bbox_.high()); + min_dist = 10.0*diag; + if (!hasSurface()) + return result; + + int code; + int classtype = getSurface(0)->instanceType(code); + if (classtype != Class_Plane && classtype != Class_Cylinder && + classtype != Class_Cone) + return result; // For the time being + + shared_ptr<ParamSurface> surf = getSurface(0)->surface(); + shared_ptr<ElementarySurface> elem = + dynamic_pointer_cast<ElementarySurface,ParamSurface>(surf); + + Point vec = elem->direction(); + Point loc = elem->location(); + double rad = elem->radius(0.0, 0.0); + double alpha = 0.0; + if (elem->instanceType() == Class_Cone) + { + shared_ptr<Cone> cone = dynamic_pointer_cast<Cone,ElementarySurface>(elem); + alpha = cone->getConeAngle(); + } + + // Check orientation. Apply to plane + bool plane = (elem->instanceType() == Class_Plane); + if (plane) + { + Point normal = group_points_[0]->getTriangNormal(); + if (vec*normal < 0.0) + vec *= -1; + if (!outer) + vec *= -1; + } + + double upar, vpar, dist; + Point close; + double eps = 1.0e-6; + for (size_t ki=0; ki<points.size(); ++ki) + { + Vector3D xyz = points[ki]->getPoint(); + Point pt(xyz[0], xyz[1], xyz[2]); + if (plane) + { + elem->closestPoint(pt, upar, vpar, close, dist, eps); + if (dist < tol || (pt-close)*vec > 0.0) + { + min_dist = std::min(min_dist, dist); + result.push_back(points[ki]); + } + } + else + { + double vval = (pt-loc)*vec; + Point pt2 = pt - vval*vec; + dist = loc.dist(pt2); + double dist2 = vval*tan(alpha); + dist -= dist2; + if ((outer && dist < rad) || (!outer && dist > rad)) + { + min_dist = std::min(min_dist, dist); + result.push_back(points[ki]); + } + } + } + return result; +} + +//=========================================================================== +bool +RevEngRegion::analyseCylinderContext(vector<pair<shared_ptr<ElementarySurface>, RevEngRegion*> >& adj, + double tol, double angtol, Point mainaxis[3], int mode, + vector<pair<shared_ptr<ElementarySurface>, RevEngRegion*> >& adj_planar, + Point& pos, Point& axis, Point& Cx, double& rad, + vector<RevEngPoint*>& cyl_pts) +//=========================================================================== +{ + for (size_t ki=0; ki<adj.size(); ++ki) + { + if (adj[ki].first->instanceType() == Class_Plane) + adj_planar.push_back(adj[ki]); + if (mode > 1 && adj[ki].first->instanceType() == Class_Cylinder) + adj_planar.push_back(adj[ki]); + } + + if (adj_planar.size() < 2) + return false; + + for (size_t ki=0; ki<adj_planar.size(); ++ki) + for (size_t kj=ki+1; kj<adj_planar.size(); ++kj) + if (adj_planar[kj].second->numPoints() > adj_planar[ki].second->numPoints()) + std::swap(adj_planar[ki], adj_planar[kj]); + +#ifdef DEBUG_CYLCONTEXT + std::ofstream ofadj("adj_planes.g2"); + for (size_t ki=0; ki<adj_planar.size(); ++ki) + { + adj_planar[ki].first->writeStandardHeader(ofadj); + adj_planar[ki].first->write(ofadj); + } +#endif + + // Find feasible axis directions + vector<Point> dir; + double acute_lim = 0.25*M_PI; + for (size_t ki=0; ki<adj_planar.size(); ++ki) + { + Point dir1 = adj_planar[ki].first->direction(); + if (mode > 1) + dir.push_back(dir1); + for (size_t kj=ki+1; kj<adj_planar.size(); ++kj) + { + Point dir2 = adj_planar[kj].first->direction(); + double ang = dir1.angle(dir2); + ang = std::min(ang, M_PI-ang); + if (ang > angtol && ang < acute_lim) + continue; + + if (mode == 1 && ang <= angtol) + { + if (dir1*dir2 < 0.0) + dir2 *= -1; + dir.push_back(0.5*(dir1 + dir2)); + } + if (ang > angtol) + dir.push_back(dir1.cross(dir2)); + } + } + + // Clean up in directions + for (size_t ki=0; ki<dir.size(); ++ki) + for (size_t kj=ki+1; kj<dir.size(); ) + { + double ang = dir[ki].angle(dir[kj]); + ang = std::min(ang, M_PI-ang); + if (ang < angtol) + dir.erase(dir.begin()+kj); + else + ++kj; + } + if (dir.size() < 1) + return false; + + // Find best candidate direction + double ang_lim = 0.1*M_PI; + double pihalf = 0.5*M_PI; + for (size_t ki=0; ki<dir.size(); ++ki) + dir[ki].normalize(); + + // Check feasability of cylinder + vector<vector<RevEngPoint*> > dir_pts(dir.size()); + for (size_t kj=0; kj<group_points_.size(); ++kj) + { + Point norm = group_points_[kj]->getLocFuncNormal(); + Point norm2 = group_points_[kj]->getTriangNormal(); + for (size_t ki=0; ki<dir.size(); ++ki) + { + double ang = dir[ki].angle(norm); + double ang2 = dir[ki].angle(norm2); + if (std::min(fabs(pihalf-ang2), fabs(pihalf-ang)) < ang_lim) + dir_pts[ki].push_back(group_points_[kj]); + } + } + + vector<double> MAH(dir.size(), 0.0); + vector<double> MAK(dir.size(), 0.0); + for (size_t ki=0; ki<dir.size(); ++ki) + { + for (size_t kj=0; kj<dir_pts[ki].size(); ++kj) + { + MAK[ki] += fabs(dir_pts[ki][kj]->GaussCurvature()); + MAH[ki] += fabs(dir_pts[ki][kj]->meanCurvature()); + } + MAK[ki] /= (double)dir_pts[ki].size(); + MAH[ki] /= (double)dir_pts[ki].size(); + } + + int min_frac = std::numeric_limits<double>::max(); + int ix = -1; + double eps = 1.0e-9; + double num_frac = 0.25; + double min_num = num_frac*(double)group_points_.size(); + for (size_t ki=0; ki<dir.size(); ++ki) + { + if ((double)dir_pts[ki].size() < min_num) + continue; + double frac = (MAH[ki]<eps) ? 1.0e8 : MAK[ki]/MAH[ki]; + if (frac < min_frac) + { + min_frac = frac; + ix = (int)ki; + } + } + + if (ix < 0) + return false; + +#ifdef DEBUG_CYLCONTEXT + std::ofstream of2("cyl_cand_pts.g2"); + of2 << "400 1 0 4 0 255 0 255" << std::endl; + of2 << dir_pts[ix].size() << std::endl; + for (size_t kj=0; kj<dir_pts[ix].size(); ++kj) + of2 << dir_pts[ix][kj]->getPoint() << std::endl; +#endif + + vector<vector<RevEngPoint*> > conn_groups; + vector<RevEngPoint*> dummy; + connectedGroups(dir_pts[ix], conn_groups, false, dummy); + int min_conn = 0; + int conn_ix = -1; + for (size_t ki=0; ki<conn_groups.size(); ++ki) + if ((int)conn_groups[ki].size() > min_conn) + { + min_conn = (int)conn_groups[ki].size(); + conn_ix = (int)ki; + } + + if ((double)conn_groups[conn_ix].size() >= min_num) + { + // Candidate found + // Compute cylinder centre and radius. Project points + axis = dir[ix]; + vector<pair<vector<RevEngPoint*>::iterator, + vector<RevEngPoint*>::iterator> > group; + group.push_back(std::make_pair(conn_groups[conn_ix].begin(), + conn_groups[conn_ix].end())); + Point mid = 0.5*(bbox_.low() + bbox_.high()); + vector<Point> projected; + double maxdp, avdp; + RevEngUtils::projectToPlane(group, axis, mid, projected, maxdp, avdp); + + int min_ix = -1; + double min_ang = M_PI; + for (int ka=0; ka<3; ++ka) + { + double ang = mainaxis[ka].angle(axis); + ang = std::min(ang, M_PI-ang); + if (ang < min_ang) + { + min_ix = ka; + min_ang = ang; + } + } + Cx = mainaxis[(min_ix+1)%3]; + Point Cy = axis.cross(Cx); + Cy.normalize(); + Cx = Cy.cross(axis); + Cx.normalize(); + + RevEngUtils::computeCircPosRadius(projected, axis, Cx, Cy, pos, rad); + + cyl_pts.insert(cyl_pts.end(), conn_groups[conn_ix].begin(), + conn_groups[conn_ix].end()); + return true; + } + + return false; +} + +//=========================================================================== +bool +RevEngRegion::identifySignificantAxis(vector<pair<shared_ptr<ElementarySurface>, RevEngRegion*> >& adj, + Point& pos, Point& axis, Point& axis2) +//=========================================================================== +{ + // Currently applicable only for point groups with an associated plane + if (!hasSurface()) + return false; + int code; + int classtype = getSurface(0)->instanceType(code); + if (classtype != Class_Plane && classtype != Class_Sphere) + return false; + + shared_ptr<ParamSurface> surf = getSurface(0)->surface(); + shared_ptr<ElementarySurface> elem = + dynamic_pointer_cast<ElementarySurface,ParamSurface>(surf); + if (!elem.get()) + return false; // Should not happen + + Point norm = elem->direction(); + double ang1 = norm.angle(normalcone_.centre()); + double ang2 = norm.angle(normalcone2_.centre()); + double ang3 = norm.angle(avnorm_); + double ang4 = norm.angle(avnorm2_); + double anglim = 0.1*M_PI; + if (ang1 > anglim && ang2 > anglim && ang3 > anglim && ang4 > anglim) + return false; // Surface orientation is incompatible with point cloud + + double min_ang = M_PI; + for (size_t ki=0; ki<adj.size(); ++ki) + { + if (adj[ki].first->instanceType() != Class_Cylinder && + adj[ki].first->instanceType() != Class_Cone && + adj[ki].first->instanceType() != Class_Torus) + continue; + if (adj[ki].second->getSurfaceFlag() >= ACCURACY_POOR) + continue; + Point dir = adj[ki].first->direction(); + double ang = norm.angle(dir); + ang = std::min(M_PI,ang); + if (ang < min_ang) + { + min_ang = ang; + axis = dir; + axis2 = adj[ki].first->direction2(); + pos = adj[ki].first->location(); + } + } + + if (axis.dimension() == 0 || min_ang > anglim) + return false; + else + return true; +} + + +//=========================================================================== +void +RevEngRegion::analyseRotated(Point& pos, Point& axis, Point& axis2) +//=========================================================================== +{ + + vector<Point> rotated; + vector<pair<vector<RevEngPoint*>::iterator, + vector<RevEngPoint*>::iterator> > group; + group.push_back(std::make_pair(group_points_.begin(), group_points_.end())); + RevEngUtils::rotateToPlane(group, axis2, axis, pos, rotated); + + Point low = bbox_.low(); + Point high = bbox_.high(); + double len = low.dist(high); + +#ifdef DEBUG_VALIDATE + std::ofstream of("rotated_points.g2"); + of << "400 1 0 4 255 0 0 255" << std::endl; + of << rotated.size() << std::endl; + for (size_t kr=0; kr<rotated.size(); ++kr) + of << rotated[kr] << std::endl; + of << "410 1 0 4 0 0 255 255" << std::endl; + of << "1" << std::endl; + of << pos-0.5*len*axis << " " << pos+0.5*len*axis << std::endl; + of << "410 1 0 4 0 255 0 255" << std::endl; + of << "1" << std::endl; + of << pos-0.5*len*axis2 << " " << pos+0.5*len*axis2 << std::endl; +#endif + + int stop_break = 1; +} + +//=========================================================================== +shared_ptr<Torus> +RevEngRegion::analyseRotatedTorus(Point& pos, Point& Cx, Point& axis, + double tol, double angtol) +//=========================================================================== +{ + // Compute minor circle of torus given rotational axis + vector<Point> rotated; + vector<pair<vector<RevEngPoint*>::iterator, + vector<RevEngPoint*>::iterator> > group; + group.push_back(std::make_pair(group_points_.begin(), group_points_.end())); + RevEngUtils::rotateToPlane(group, Cx, axis, pos, rotated); + + Point low = bbox_.low(); + Point high = bbox_.high(); + double len = low.dist(high); + +#ifdef DEBUG_EXTRACT + std::ofstream of("rotated_points_tor.g2"); + of << "400 1 0 4 255 0 0 255" << std::endl; + of << rotated.size() << std::endl; + for (size_t kr=0; kr<rotated.size(); ++kr) + of << rotated[kr] << std::endl; + of << "410 1 0 4 0 0 255 255" << std::endl; + of << "1" << std::endl; + of << pos-0.5*len*axis << " " << pos+0.5*len*axis << std::endl; + of << "410 1 0 4 0 255 0 255" << std::endl; + of << "1" << std::endl; + of << pos-0.5*len*Cx << " " << pos+0.5*len*Cx << std::endl; +#endif + + Point cpos; + double crad; + Point Cy = axis.cross(Cx); + RevEngUtils::computeCircPosRadius(rotated, Cy, Cx, axis, cpos, crad); + shared_ptr<Circle> circ(new Circle(crad, cpos, Cy, Cx)); +#ifdef DEBUG_EXTRACT + circ->writeStandardHeader(of); + circ->write(of); +#endif + Point cvec = cpos - pos; + double R1 = (cvec - (cvec*axis)*axis).length(); + double R2 = (cvec*axis)*axis.length(); + shared_ptr<Torus> tor(new Torus(R1, crad, pos+R2*axis, axis, Cy)); + +#ifdef DEBUG_EXTRACT + tor->writeStandardHeader(of); + tor->write(of); +#endif + + // Check accuracy + double maxd, avd; + int num, num2; + vector<RevEngPoint*> in, out; + vector<pair<double, double> > dist_ang; + vector<double> parvals; + RevEngUtils::distToSurf(group_points_.begin(), group_points_.end(), + tor, tol, maxd, avd, num, num2, in, out, + parvals, dist_ang, angtol); + int sf_flag = defineSfFlag(0, tol, num, num2, avd, false); + if (sf_flag == ACCURACY_OK) + { + // Finished + return tor; + } + + vector<RevEngPoint*> cyl_pts1, cyl_pts2, remaining1, remaining2; + int sgn = (avH_ < 0.0) ? 1 : -1; + RevEngUtils::extractLinearPoints(group_points_, rotated, + len, pos, axis, R1+sgn*crad, axis, false, + tol, angtol, dist_ang, + cyl_pts1, true, remaining1); + RevEngUtils::extractLinearPoints(group_points_, rotated, + len, pos, axis, R1+sgn*crad, axis, false, + tol, angtol, dist_ang, + cyl_pts2, false, remaining2); + +#ifdef DEBUG_EXTRACT + if (cyl_pts1.size() > 0) + { + of << "400 1 0 4 255 0 0 255" << std::endl; + of << cyl_pts1.size() << std::endl; + for (size_t ki=0; ki<cyl_pts1.size(); ++ki) + of << cyl_pts1[ki]->getPoint() << std::endl; + } + if (cyl_pts2.size() > 0) + { + of << "400 1 0 4 255 0 0 255" << std::endl; + of << cyl_pts2.size() << std::endl; + for (size_t ki=0; ki<cyl_pts2.size(); ++ki) + of << cyl_pts2[ki]->getPoint() << std::endl; + } +#endif + + vector<RevEngPoint*> distpt, angpt; + identifyDistPoints(dist_ang, tol, maxd, avd, distpt); + identifyAngPoints(dist_ang, angtol, tol, angpt); +#ifdef DEBUG_EXTRACT + std::ofstream of2("dist_ang_out.g2"); + if (distpt.size() > 0) + { + of2 << "400 1 0 4 55 200 0 255" << std::endl; + of2 << distpt.size() << std::endl; + for (size_t ki=0; ki<distpt.size(); ++ki) + of2 << distpt[ki]->getPoint() << std::endl; + } + if (angpt.size() > 0) + { + of2 << "400 1 0 4 55 0 200 255" << std::endl; + of2 << angpt.size() << std::endl; + for (size_t ki=0; ki<angpt.size(); ++ki) + of2 << angpt[ki]->getPoint() << std::endl; + } +#endif + int stop_break = 1; + return tor; +} + +//=========================================================================== +bool +RevEngRegion::analyseTorusContext(vector<pair<shared_ptr<ElementarySurface>, RevEngRegion*> >& adj, + double tol, double angtol, vector<size_t>& adjacent_ix, + int &plane_ix, int& cyl_ix, + Point& pos, Point& axis, Point& Cx, double& R1, + double& R2, double dom[4], bool& outer, + bool& analyse_rotated) +//=========================================================================== +{ + for (size_t ki=0; ki<adj.size(); ++ki) + for (size_t kj=ki+1; kj<adj.size(); ++kj) + if (adj[kj].second->numPoints() > adj[ki].second->numPoints()) + std::swap(adj[ki], adj[kj]); + + analyse_rotated = false; + plane_ix=-1; + cyl_ix=-1; + //vector<Point> dir; + vector<pair<size_t, size_t> > combo; + vector<pair<int, int> > num_common; + vector<double> angle; + for (size_t ki=0; ki<adj.size(); ++ki) + { + shared_ptr<ElementarySurface> elem = adj[ki].first; + if (elem->instanceType() != Class_Plane) + continue; + Point plane_axis = elem->direction(); + for (size_t kj=0; kj<adj.size(); ++kj) + { + shared_ptr<ElementarySurface> elem2 = adj[kj].first; + if (elem2->instanceType() != Class_Cylinder) + continue; + Point cyl_axis = elem2->direction(); + double ang = plane_axis.angle(cyl_axis); + ang = std::min(ang, M_PI-ang); + if (ang < angtol) + { + combo.push_back(std::make_pair(ki, kj)); + vector<RevEngPoint*> adj_pt1 = extractNextToAdjacent(adj[ki].second); + vector<RevEngPoint*> adj_pt2 = extractNextToAdjacent(adj[kj].second); + num_common.push_back(std::make_pair((int)adj_pt1.size(), (int)adj_pt2.size())); + angle.push_back(ang); + } + } + } + + // for (size_t ki=0; ki<adj.size(); ++ki) + // { + // shared_ptr<ElementarySurface> elem = adj[ki].first; + // if (!(elem->instanceType() == Class_Plane || elem->instanceType() == Class_Cylinder)) + // continue; + + // Point curr_dir = elem->direction(); + // dir.push_back(curr_dir); + // adjacent_ix.push_back(ki); + // if (elem->instanceType() == Class_Plane) + // { + // plane = true; + // plane_ix = (int)ki; + // } + // else + // { + // cyl = true; + // pos = elem->location(); + // Cx = elem->direction2(); + // radius = elem->radius(0.0, 0.0); + // cyl_ix = (int)ki; + // } + + // for (size_t kj=ki+1; kj<adj.size(); ++kj) + // { + // if (!(adj[kj].first->instanceType() == Class_Plane || + // adj[kj].first->instanceType() == Class_Cylinder)) + // continue; + // curr_dir = adj[kj].first->direction(); + // double ang = dir[0].angle(curr_dir); + // ang = std::min(ang, M_PI-ang); + // if (ang < angtol) + // { + // dir.push_back(curr_dir); + // adjacent_ix.push_back(kj); + // if (adj[kj].first->instanceType() == Class_Plane) + // { + // plane = true; + // if (plane_ix < 0) + // plane_ix = (int)kj; + // } + // else + // { + // if (!cyl) + // { + // pos = adj[kj].first->location(); + // Cx = adj[kj].first->direction2(); + // radius = adj[kj].first->radius(0.0, 0.0); + // cyl_ix = (int)kj; + // } + // cyl = true; + // } + // } + // } + + // if (plane && cyl) + // { + // combo.push_back(plane_ix, cyl_ix); + + // break; + // else + // { + // plane = false; + // cyl = false; + // dir.clear(); + // adjacent_ix.clear(); + // plane_ix = cyl_ix = -1; + // } + // } + + if (combo.size() == 0) + return false; + + double fac = 1.1; + int max_num = 0; + int ix = -1; + double min_ang = M_PI; + for (size_t ki=0; ki<combo.size(); ++ki) + { + if (num_common[ki].first+num_common[ki].second > max_num /*&& angle[ki] < fac*min_ang*/) + { + max_num = num_common[ki].first+num_common[ki].second; + min_ang = angle[ki]; + ix = (int)ki; + } + } + + if (ix < 0) + return false; + + plane_ix = (int)combo[ix].first; + cyl_ix = (int)combo[ix].second; + pos = adj[cyl_ix].first->location(); + double radius = adj[cyl_ix].first->radius(0.0, 0.0); + + // if (plane && cyl) + // { + // // Compute axis + // for (size_t ki=1; ki<dir.size(); ++ki) + // if (dir[0]*dir[ki] < 0.0) + // dir[ki] *= -1; + + // axis = Point(0.0, 0.0, 0.0); + // double frac = 1.0/(double)dir.size(); + // for (size_t ki=0; ki<dir.size(); ++ki) + // axis += frac*dir[ki]; + outer = true; + axis = adj[plane_ix].first->direction(); + Point axis2 = adj[cyl_ix].first->direction(); + +#ifdef DEBUG_TORUSCONTEXT + std::ofstream of("adj_elem.g2"); + for (size_t ki=0; ki<adjacent_ix.size(); ++ki) + { + adj[adjacent_ix[ki]].first->writeStandardHeader(of); + adj[adjacent_ix[ki]].first->write(of); + adj[adjacent_ix[ki]].second->writeRegionInfo(of); + } +#endif + + Cx = adj[cyl_ix].first->direction2(); + Point Cy = axis.cross(Cx); + Cx = Cy.cross(axis); // Project to plane + +#ifdef DEBUG_TORUSCONTEXT + // Check accuracy of alternative plane + Point loc = adj[cyl_ix].first->location(); + Point mid(0.0, 0.0, 0.0); + double wgt = 1.0/(double)(adj[plane_ix].second->numPoints()); + for (auto it=adj[plane_ix].second->pointsBegin(); + it!=adj[plane_ix].second->pointsEnd(); ++it) + { + Vector3D pos0 = (*it)->getPoint(); + Point xpos(pos0[0], pos0[1], pos0[2]); + Point vec = xpos - loc; + Point pos2 = loc + (vec*axis2)*axis2; + mid += wgt*pos2; + } + shared_ptr<Plane> plane(new Plane(mid, axis2)); + vector<RevEngPoint*> inptp, outptp; + vector<pair<double, double> > dist_angp; + double maxdp, avdp; + int num_inp, num2_inp; + vector<double> parvalsp; + RevEngUtils::distToSurf(adj[plane_ix].second->pointsBegin(), + adj[plane_ix].second->pointsEnd(), + plane, tol, maxdp, avdp, num_inp, num2_inp, + inptp, outptp, parvalsp, dist_angp, -1.0); + + std::ofstream ofd1("in_out_alt_plane.g2"); + ofd1 << "400 1 0 4 155 50 50 255" << std::endl; + ofd1 << inptp.size() << std::endl; + for (size_t kr=0; kr<inptp.size(); ++kr) + ofd1 << inptp[kr]->getPoint() << std::endl; + ofd1 << "400 1 0 4 50 155 50 255" << std::endl; + ofd1 << outptp.size() << std::endl; + for (size_t kr=0; kr<outptp.size(); ++kr) + ofd1 << outptp[kr]->getPoint() << std::endl; + + // Check accuracy of alternative cylinder + vector<pair<vector<RevEngPoint*>::iterator, + vector<RevEngPoint*>::iterator> > points; + points.push_back(std::make_pair(adj[cyl_ix].second->pointsBegin(), + adj[cyl_ix].second->pointsEnd())); + BoundingBox bb = adj[cyl_ix].second->getBbox(); + Point xpos; + double rad; + Point low = bb.low(); + Point high = bb.high(); + RevEngUtils::computeCylPosRadius(points, low, high, axis, Cx, Cy, + xpos, rad); + shared_ptr<Cylinder> cyl(new Cylinder(rad, xpos, axis, Cy)); + vector<RevEngPoint*> inpt, outpt; + vector<pair<double, double> > dist_ang; + double maxd, avd; + int num_in, num2_in; + vector<double> parvals; + RevEngUtils::distToSurf(points[0].first, points[0].second, + cyl, tol, maxd, avd, num_in, num2_in, + inpt, outpt, parvals, dist_ang, -1.0); + + std::ofstream ofd2("in_out_alt_cyl.g2"); + ofd2 << "400 1 0 4 155 50 50 255" << std::endl; + ofd2 << inpt.size() << std::endl; + for (size_t kr=0; kr<inpt.size(); ++kr) + ofd2 << inpt[kr]->getPoint() << std::endl; + ofd2 << "400 1 0 4 50 155 50 255" << std::endl; + ofd2 << outpt.size() << std::endl; + for (size_t kr=0; kr<outpt.size(); ++kr) + ofd2 << outpt[kr]->getPoint() << std::endl; +#endif + + // Bound cylinder + int num_pt = adj[cyl_ix].second->numPoints(); + double dist, ang; + int ka; + int num_in_cyl = 0; + for (ka=0; ka<num_pt; ++ka) + { + Vector2D uv = adj[cyl_ix].second->getPoint(ka)->getPar(); + adj[cyl_ix].second->getPoint(ka)->getSurfaceDist(dist, ang); + if (ang <= angtol) + { + num_in_cyl++; + dom[0] = dom[1] = uv[0]; + dom[2] = dom[3] = uv[1]; + break; + } + } + for (; ka<num_pt; ++ka) + { + Vector2D uv = adj[cyl_ix].second->getPoint(ka)->getPar(); + adj[cyl_ix].second->getPoint(ka)->getSurfaceDist(dist, ang); + if (ang > angtol) + continue; + num_in_cyl++; + dom[0] = std::min(dom[0], uv[0]); + dom[1] = std::max(dom[1], uv[0]); + dom[2] = std::min(dom[2], uv[1]); + dom[3] = std::max(dom[3], uv[1]); + } + if (dom[1] - dom[2] > 2*M_PI) + { + dom[0] = 0.0; + dom[1] = 2*M_PI; + } + + if (num_in_cyl < 10) + return false; + +#ifdef DEBUG_TORUSCONTEXT + shared_ptr<ElementarySurface> elem2(adj[cyl_ix].first->clone()); + elem2->setParameterBounds(dom[0], dom[2], dom[1], dom[3]); + std::ofstream ofcyl("bd_cyl.g2"); + elem2->writeStandardHeader(ofcyl); + elem2->write(ofcyl); +#endif + + // Compute distance from cylinder to plane + Point pos1 = adj[cyl_ix].first->point(0.5*(dom[0]+dom[1]), dom[2]); + Point pos2 = adj[cyl_ix].first->point(0.5*(dom[0]+dom[1]), dom[3]); + double upar1, upar2, upar3, vpar1, vpar2, vpar3, dist1, dist2, dist3; + Point close1, close2, close3; + double eps = 1.0e-6; + adj[plane_ix].first->closestPoint(pos1, upar1, vpar1, close1, dist1, eps); + adj[plane_ix].first->closestPoint(pos2, upar2, vpar2, close2, dist2, eps); + Point pos3 = (dist1 < dist2) ? pos + dom[2]*axis2 : pos + dom[3]*axis2; + adj[plane_ix].first->closestPoint(pos3, upar3, vpar3, close3, dist3, eps); + + if ((close1-pos1)*axis < 0.0) + axis *= -1; + + if ((close1-pos1)*(close2-pos2) < 0.0) + { + analyse_rotated = true; + + // Check axis direction + int num1 = 0, num2 = 0; + for (size_t ki=0; ki<group_points_.size(); ++ki) + { + Vector3D xyz = group_points_[ki]->getPoint(); + Point gpt(xyz[0], xyz[1], xyz[2]); + if ((gpt-pos)*axis < 0.0) + num1++; + else if ((gpt-pos)*axis > 0.0) + num2++; + } + if (num2 < num1) + axis *= -1; + } + + R2 = std::min(dist1, dist2); + R1 = radius - R2; + pos = close3; + + // Check if the torus in inwards or outwards + double cdist; + //RevEngPoint *closest_planar = + (void)adj[plane_ix].second->closestPoint(pos, cdist); + if (cdist > 0.99*radius) + { + outer = false; + R1 = radius + R2; + } + +#ifdef DEBUG_TORUSCONTEXT + // Bound plane + double dom2[4]; + int num_pt2 = adj[plane_ix].second->numPoints(); + Vector2D uv2 = adj[plane_ix].second->getPoint(0)->getPar(); + dom2[0] = dom2[1] = uv2[0]; + dom2[2] = dom2[3] = uv2[1]; + + for (int ka=0; ka<num_pt2; ++ka) + { + Vector2D uv2 = adj[plane_ix].second->getPoint(ka)->getPar(); + dom2[0] = std::min(dom2[0], uv2[0]); + dom2[1] = std::max(dom2[1], uv2[0]); + dom2[2] = std::min(dom2[2], uv2[1]); + dom2[3] = std::max(dom2[3], uv2[1]); + } + shared_ptr<ElementarySurface> elem3(adj[plane_ix].first->clone()); + elem3->setParameterBounds(dom2[0], dom2[2], dom2[1], dom2[3]); + std::ofstream ofpl("bd_plane.g2"); + elem3->writeStandardHeader(ofpl); + elem3->write(ofpl); +#endif + + return true; + // } + + // return false; // Requested configuration not found +} + +//=========================================================================== +RevEngPoint* RevEngRegion::closestPoint(const Point& pos, double& dist) +//=========================================================================== +{ + dist = std::numeric_limits<double>::max(); + int ix = -1; + for (size_t ki=0; ki<group_points_.size(); ++ki) + { + Vector3D xyz = group_points_[ki]->getPoint(); + Point pt(xyz[0], xyz[1], xyz[2]); + double curr_dist = pos.dist(pt); + if (curr_dist < dist) + { + dist = curr_dist; + ix = (int)ki; + } + } + + if (ix >= 0) + return group_points_[ix]; + else + return 0; +} + +//=========================================================================== +RevEngPoint* RevEngRegion::closestParPoint(const Point& parpt, double& dist) +//=========================================================================== +{ + if (!hasSurface()) + return 0; + + dist = std::numeric_limits<double>::max(); + int ix = -1; + for (size_t ki=0; ki<group_points_.size(); ++ki) + { + Vector2D uv = group_points_[ki]->getPar(); + Point pt(uv[0], uv[1]); + double curr_dist = parpt.dist(pt); + if (curr_dist < dist) + { + dist = curr_dist; + ix = (int)ki; + } + } + + if (ix >= 0) + return group_points_[ix]; + else + return 0; +} + +//=========================================================================== +bool RevEngRegion::extractTorus(Point mainaxis[3], double tol, int min_pt, + int min_pt_reg, double angtol, + int prefer_elementary, + vector<shared_ptr<HedgeSurface> >& hedgesfs, + vector<HedgeSurface*>& prevsfs, + vector<vector<RevEngPoint*> >& out_groups) +//=========================================================================== +{ + bool found = false; + int min_nmb = 20; + if ((int)group_points_.size() < min_nmb) + return false; + + // std::ofstream of("curr_region.g2"); + // writeRegionInfo(of); + + vector<Point> adj_axis; + axisFromAdjacent(angtol, adj_axis); + size_t num_adj = adj_axis.size(); + for (int ka=0; ka<3; ++ka) + { + size_t kj; + for (kj=0; kj<num_adj; ++kj) + { + double ang = mainaxis[ka].angle(adj_axis[kj]); + ang = std::min(ang, M_PI-ang); + if (ang <= angtol) + break; + } + if (kj == num_adj) + adj_axis.push_back(mainaxis[ka]); + } + shared_ptr<Torus> tor1 = computeTorus(group_points_, adj_axis, tol, + angtol); + if (!tor1.get()) + return false; + if (tor1->getMajorRadius() <= tor1->getMinorRadius()) + return false; + + // Check accuracy + double maxd1, avd1, maxd2=100*tol, avd2=100*tol; + int num1, num1_2, num2=0, num2_2=0; + //shared_ptr<ParamSurface> surf = cyl; + vector<RevEngPoint*> in1, out1,in2, out2; + vector<pair<double, double> > dist_ang1; + vector<pair<double, double> > dist_ang2; + vector<double> parvals1; + vector<double> parvals2; + RevEngUtils::distToSurf(group_points_.begin(), group_points_.end(), + tor1, tol, maxd1, avd1, num1, num1_2, in1, out1, + parvals1, dist_ang1, angtol); + int sf_flag1 = defineSfFlag(0, tol, num1, num1_2, avd1, false); + +#ifdef DEBUG_EXTRACT + std::ofstream ofd("in_out_tor.g2"); + ofd << "400 1 0 4 155 50 50 255" << std::endl; + ofd << in1.size() << std::endl; + for (size_t kr=0; kr<in1.size(); ++kr) + ofd << in1[kr]->getPoint() << std::endl; + ofd << "400 1 0 4 50 155 50 255" << std::endl; + ofd << out1.size() << std::endl; + for (size_t kr=0; kr<out1.size(); ++kr) + ofd << out1[kr]->getPoint() << std::endl; + // ofd << "400 1 0 4 155 50 50 255" << std::endl; + // ofd << in2.size() << std::endl; + // for (size_t kr=0; kr<in2.size(); ++kr) + // ofd << in2[kr]->getPoint() << std::endl; + // ofd << "400 1 0 4 50 155 50 255" << std::endl; + // ofd << out2.size() << std::endl; + // for (size_t kr=0; kr<out2.size(); ++kr) + // ofd << out2[kr]->getPoint() << std::endl; +#endif + + shared_ptr<Torus> tor2; + if (sf_flag1 > ACCURACY_OK) + { + Point pos = tor1->location(); + Point axis = tor1->direction(); + Point Cx = tor1->direction2(); + tor2 = analyseRotatedTorus(pos, Cx, axis, tol, angtol); + RevEngUtils::distToSurf(group_points_.begin(), group_points_.end(), + tor2, tol, maxd2, avd2, num2, num2_2, in2, out2, + parvals2, dist_ang2, angtol); + } + + size_t insize = std::max(in1.size(), in2.size()); + if (insize > group_points_.size()/2 && (int)insize > min_nmb) + { + shared_ptr<Torus> tor_in2; + shared_ptr<Torus> tor_in1 = + computeTorus(in1.size() > in2.size() ? in1 : in2, adj_axis, + tol, angtol); +if (tor_in1.get()) +{ + vector<RevEngPoint*> inpt_in1, outpt_in1, inpt_in2, outpt_in2; + vector<pair<double, double> > dist_ang_in1, dist_ang_in2; + double maxd_in1, avd_in1, maxd_in2, avd_in2; + int num1_in, num1_in2, num2_in, num2_in2; + vector<double> parvals_in1; + vector<double> parvals_in2; + RevEngUtils::distToSurf(group_points_.begin(), group_points_.end(), + tor_in1, tol, maxd_in1, avd_in1, num1_in, num1_in2, + inpt_in1, outpt_in1, parvals_in1, dist_ang_in1, + angtol); + + // RevEngUtils::distToSurf(group_points_.begin(), group_points_.end(), + // tor_in2, tol, maxd_in2, avd_in2, num2_in, num2_in2, + // inpt_in2, outpt_in2, parvals_in2, + // dist_ang_in2, angtol); + +#ifdef DEBUG_EXTRACT + std::ofstream ofd2("in_out_tor2.g2"); + ofd2 << "400 1 0 4 155 50 50 255" << std::endl; + ofd2 << inpt_in1.size() << std::endl; + for (size_t kr=0; kr<inpt_in1.size(); ++kr) + ofd2 << inpt_in1[kr]->getPoint() << std::endl; + ofd2 << "400 1 0 4 50 155 50 255" << std::endl; + ofd2 << outpt_in1.size() << std::endl; + for (size_t kr=0; kr<outpt_in1.size(); ++kr) + ofd2 << outpt_in1[kr]->getPoint() << std::endl; + // ofd2 << "400 1 0 4 155 50 50 255" << std::endl; + // ofd2 << inpt_in2.size() << std::endl; + // for (size_t kr=0; kr<inpt_in2.size(); ++kr) + // ofd2 << inpt_in2[kr]->getPoint() << std::endl; + // ofd2 << "400 1 0 4 50 155 50 255" << std::endl; + // ofd2 << outpt_in2.size() << std::endl; + // for (size_t kr=0; kr<outpt_in2.size(); ++kr) + // ofd2 << outpt_in2[kr]->getPoint() << std::endl; +#endif + + if (num1_in > num1 || avd_in1 < avd1) + { + std::swap(tor1, tor_in1); + std::swap(num1, num1_in); + std::swap(num1_2, num1_in2); + std::swap(avd1, avd_in1); + std::swap(maxd1, maxd_in1); + std::swap(parvals1, parvals_in1); + std::swap(dist_ang1, dist_ang_in1); + // std::cout << "Torus swap 1" << std::endl; + // std::cout << group_points_.size() << " " << num1_in << " "; + // std::cout << num1 << " " << avd_in1 << " " << avd1; + // std::cout << " " << maxd_in1 << " " << maxd1 << std::endl; + } + // if (num2_in > num2 || avd_in2 < avd2) + // { + // std::swap(tor2, tor_in2); + // std::swap(num2, num2_in); + // std::swap(num2_2, num2_in2); + // std::swap(avd2, avd_in2); + // std::swap(maxd2, maxd_in2); + // std::swap(parvals2, parvals_in2); + // std::swap(dist_ang2, dist_ang_in2); + // // std::cout << "Torus swap 2" << std::endl; + // // std::cout << group_points_.size() << " " << num2_in << " "; + // // std::cout << num2 << " " << avd_in2 << " " << avd2; + // // std::cout << " " << maxd_in2 << " " << maxd2 << std::endl; + // } + } + } + +//int num = (int)group_points_.size(); + double maxd_init, avd_init; + int num_init, num_init2; + getAccuracy(maxd_init, avd_init, num_init, num_init2); + int sf_flag2 = defineSfFlag(0, tol, num2, num2_2, avd2, false); + if (tor1->getMajorRadius() > tor1->getMinorRadius() && + sf_flag1 < ACCURACY_POOR && num1 > num2) + { + bool OK = true; + if (associated_sf_.size() > 0) + { + // Check with current approximating surface + double acc_fac1 = 1.25; + double acc_fac2 = 0.75; + if (surfflag_ == ACCURACY_OK && sf_flag1 > surfflag_) + OK = false; + else if (prefer_elementary == ALWAYS_ELEM) + OK = false; + else if (prefer_elementary == PREFER_ELEM && + ((double)num1 < acc_fac1*num_init || + avd1 > acc_fac2*avd_init)) + OK = false; + else if (prefer_elementary == BEST_ACCURACY && + (num1 < num_init || avd1 > avd_init)) + OK = false; + } + + if (OK) + { + found = true; + for (size_t kh=0; kh<group_points_.size(); ++kh) + { + group_points_[kh]->setPar(Vector2D(parvals1[2*kh],parvals1[2*kh+1])); + group_points_[kh]->setSurfaceDist(dist_ang1[kh].first, dist_ang1[kh].second); + } + setAccuracy(maxd1, avd1, num1, num1_2); + +#ifdef DEBUG + std::cout << "Torus 1. N1: " << num << ", N2: " << num1 << ", max: " << maxd1 << ", av: " << avd1 << std::endl; +#endif + // associated_sf_.clear(); + // for (int ka=0; ka<divmod[0]->nmbEntities(); ++ka) + // { + //shared_ptr<ParamSurface> tor1_2 = divmod[0]->getSurface(ka); + shared_ptr<HedgeSurface> hedge(new HedgeSurface(tor1, this)); + for (size_t kh=0; kh<associated_sf_.size(); ++kh) + prevsfs.push_back(associated_sf_[kh]); + setHedge(hedge.get()); + hedgesfs.push_back(hedge); + setSurfaceFlag(sf_flag1); + } + // } + } + else if (tor2->getMajorRadius() > tor2->getMinorRadius() && + sf_flag2 < ACCURACY_POOR && num2 >= num1) + { + bool OK = true; + if (associated_sf_.size() > 0) + { + // Check with current approximating surface + double acc_fac1 = 1.25; + double acc_fac2 = 0.75; + if (surfflag_ == ACCURACY_OK && sf_flag2 > surfflag_) + OK = false; + else if (prefer_elementary == ALWAYS_ELEM) + OK = false; + else if (prefer_elementary == PREFER_ELEM && + ((double)num2 < acc_fac1*num_init || + avd2 > acc_fac2*avd_init)) + OK = false; + else if (prefer_elementary == BEST_ACCURACY && + (num2 < num_init || avd2 > avd_init)) + OK = false; + } + + if (OK) + { + found = true; + for (size_t kh=0; kh<group_points_.size(); ++kh) + { + group_points_[kh]->setPar(Vector2D(parvals2[2*kh],parvals2[2*kh+1])); + group_points_[kh]->setSurfaceDist(dist_ang2[kh].first, dist_ang2[kh].second); + } + setAccuracy(maxd2, avd2, num2, num2_2); + +#ifdef DEBUG + std::cout << "Torus 2. N1: " << num << ", N2: " << num2 << ", max: " << maxd2 << ", av: " << avd2 << std::endl; +#endif + // associated_sf_.clear(); + // for (int ka=0; ka<divmod[0]->nmbEntities(); ++ka) + // { + // shared_ptr<ParamSurface> tor2_2 = divmod[0]->getSurface(ka); + shared_ptr<HedgeSurface> hedge(new HedgeSurface(tor2, this)); + for (size_t kh=0; kh<associated_sf_.size(); ++kh) + prevsfs.push_back(associated_sf_[kh]); + setHedge(hedge.get()); + hedgesfs.push_back(hedge); + setSurfaceFlag(sf_flag2); + // } + } + } + if (!basesf_.get() || + (num1 >= num_in_base_ && avd1 < avdist_base_)) + setBaseSf(tor1, maxd1, avd1, num1, num1_2); + if (!basesf_.get() || + (num2 >= num_in_base_ && avd2 < avdist_base_)) + setBaseSf(tor2, maxd2, avd2, num2, num2_2); + + return found; +} + +//=========================================================================== + shared_ptr<Torus> RevEngRegion::computeTorus(vector<RevEngPoint*>& points, + vector<Point>& adj_axis, + double tol, double angtol) +//=========================================================================== +{ +#ifdef DEBUG_EXTRACT + std::ofstream of("torus_compute.g2"); +#endif + // Compute mean curvature and initial point in plane + double k2mean = 0.0; + double wgt = 1.0/(double)points.size(); + for (size_t kr=0; kr<points.size(); ++kr) + { + double kmax = points[kr]->maxPrincipalCurvature(); + k2mean += wgt*kmax; + } + double rd = 1.0/k2mean; + + vector<Point> centr(points.size()); + Point mid(0.0, 0.0, 0.0); + for (size_t kr=0; kr<points.size(); ++kr) + { + double kmax = points[kr]->maxPrincipalCurvature(); + k2mean += wgt*kmax; + + Vector3D xyz = points[kr]->getPoint(); + Point xyz2(xyz[0], xyz[1], xyz[2]); + Point norm = points[kr]->getLocFuncNormal(); + centr[kr] = xyz2 + rd*norm; + mid += wgt*centr[kr]; + } + +#ifdef DEBUG_EXTRACT + of << "400 1 0 4 155 100 0 255" << std::endl; + of << points.size() << std::endl; + for (size_t kr=0; kr<points.size(); ++kr) + { + of << centr[kr] << std::endl; + } +#endif + + Point low = bbox_.low(); + Point high = bbox_.high(); + double len = low.dist(high); + + ImplicitApprox impl; + impl.approxPoints(centr, 1); + + double val; + Point grad; + impl.evaluate(mid, val, grad); + grad.normalize_checked(); + + shared_ptr<Torus> dummy; + Point pos, normal; + bool found = impl.projectPoint(mid, grad, pos, normal); + if (!found) + return dummy; + double eps1 = 1.0e-8; + if (normal.length() < eps1) + return dummy; + + for (size_t kr=0; kr<adj_axis.size(); ++kr) + { + double ang = adj_axis[kr].angle(normal); + ang = std::min(ang, M_PI-ang); + if (ang < angtol) + { + normal = adj_axis[kr]; + break; + } + } + +#ifdef DEBUG_EXTRACT + of << "400 1 0 4 255 0 0 255" << std::endl; + of << "1" << std::endl; + of << pos << std::endl; + of << "410 1 0 4 255 0 0 255" << std::endl; + of << "1" << std::endl; + of << pos << " " << pos+0.5*len*normal << std::endl; +#endif + + // std::ofstream ofimpl("impl_plane.g2"); + // impl->visualize(points, ofimpl); + + Vector3D xyz = points[0]->getPoint(); + Point xyz2(xyz[0], xyz[1], xyz[2]); + Point Cx = centr[0] - xyz2; + Cx -= (Cx*normal)*normal; + Cx.normalize(); + Point Cy = Cx.cross(normal); + + double rad; + Point pnt; + try { + RevEngUtils::computeCircPosRadius(centr, normal, Cx, Cy, pnt, rad); + } + catch (...) + { + shared_ptr<Torus> dummy; + return dummy; + } + pnt -= ((pnt - pos)*normal)*normal; + shared_ptr<Circle> circ(new Circle(rad, pnt, normal, Cx)); +#ifdef DEBUG_EXTRACT + circ->writeStandardHeader(of); + circ->write(of); +#endif + +// vector<Point> rotated; +// vector<pair<vector<RevEngPoint*>::iterator, +// vector<RevEngPoint*>::iterator> > group; +// group.push_back(std::make_pair(points.begin(), points.end())); +// RevEngUtils::rotateToPlane(group, Cx, normal, pnt, rotated); +// #ifdef DEBUG_EXTRACT +// std::ofstream of3("rotated_pts_tor.g2"); +// of3 << "400 1 0 4 255 0 0 255" << std::endl; +// of3 << rotated.size() << std::endl; +// for (size_t kr=0; kr<rotated.size(); ++kr) +// of3 << rotated[kr] << std::endl; +// of3 << "410 1 0 4 0 0 255 255" << std::endl; +// of3 << "1" << std::endl; +// of3 << pnt-0.5*len*normal << " " << pnt+0.5*len*normal << std::endl; +// of3 << "410 1 0 4 0 255 0 255" << std::endl; +// of3 << "1" << std::endl; +// of3 << pnt-0.5*len*Cx << " " << pnt+0.5*len*Cx << std::endl; +// #endif +// Point cpos; +// double crad; +// RevEngUtils::computeCircPosRadius(rotated, Cy, Cx, normal, cpos, crad); +// shared_ptr<Circle> circ2(new Circle(crad, cpos, Cy, Cx)); +// #ifdef DEBUG_EXTRACT +// circ2->writeStandardHeader(of3); +// circ2->write(of3); +// #endif +// shared_ptr<SplineCurve> spl; +// Point xpos; +// vector<double> param; +// try { +// curveApprox(rotated, tol, circ2, param, spl, xpos); +// } +// catch (...) +// { +// } +// #ifdef DEBUG_EXTRACT +// if (spl.get()) +// { +// spl->writeStandardHeader(of3); +// spl->write(of3); +// } +// #endif + +// vector<Point> projected; +// double maxdp, avdp; +// RevEngUtils::projectToPlane(group, normal, pnt, projected, maxdp, avdp); + +// #ifdef DEBUG_EXTRACT +// std::ofstream ofp3("projected_pts_tor.g2"); +// ofp3 << "400 1 0 4 255 0 0 255" << std::endl; +// ofp3 << projected.size() << std::endl; +// for (size_t kr=0; kr<projected.size(); ++kr) +// ofp3 << projected[kr] << std::endl; +// circ->writeStandardHeader(ofp3); +// circ->write(ofp3); +// #endif + shared_ptr<Torus> tor1(new Torus(rad, fabs(rd), pnt, normal, Cy)); + +#ifdef DEBUG_EXTRACT + tor1->writeStandardHeader(of); + tor1->write(of); +#endif + + // Point cvec = cpos - pnt; +// double R1 = (cvec - (cvec*normal)*normal).length(); +// double R2 = (cvec*normal)*normal.length(); +// shared_ptr<Torus> tor2(new Torus(R1, crad, pnt+R2*normal, normal, Cy)); +// #ifdef DEBUG_EXTRACT +// tor2->writeStandardHeader(of); +// tor2->write(of); +// //std::cout << "Torus small radius: " << fabs(rd) << ", " << crad << std::endl; +// #endif + +// torus2 = tor2; + return tor1; +} + +//=========================================================================== +bool RevEngRegion::tryOtherSurf(int prefer_elementary, bool replace) +//=========================================================================== +{ + if (associated_sf_.size() > 0 && (!replace)) + return false; + + if (prefer_elementary == BEST_ACCURACY || + associated_sf_.size() == 0) + return true; + + if (prefer_elementary != BEST_ACCURACY && surfflag_ == ACCURACY_OK) + return false; + + if (prefer_elementary != BEST_ACCURACY && surf_adaption_ > INITIAL) + return false; + + if (surfflag_ == ACCURACY_POOR) + return true; + + if (prefer_elementary == ALWAYS_ELEM) + { + int sfcode; + ClassType type = associated_sf_[0]->instanceType(sfcode); + double fac = 5.0; + if ((type == Class_Plane || type == Class_Sphere) && MAH_ > fac*MAK_) + return true; + else + return false; + } + + // Check if the current accuracy is sufficient + int num = (int)group_points_.size(); + double maxd_init, avd_init; + int num_init, num_init2; + getAccuracy(maxd_init, avd_init, num_init, num_init2); + if ((double)num_init > 0.75*num) + return false; + else + return true; + +} + + +//=========================================================================== +bool RevEngRegion::extractFreeform(double tol, int min_pt, int min_pt_reg, + double angtol, int prefer_elementary, + vector<shared_ptr<HedgeSurface> >& hedgesfs, + vector<HedgeSurface*>& prevsfs, + vector<vector<RevEngPoint*> >& out_groups) +//=========================================================================== +{ + // std::ofstream of("curr_region.g2"); + // writeRegionInfo(of); + + // std::ofstream of2("curr_normals.g2"); + // writeUnitSphereInfo(of2); + + bool found = false; + int min_nmb = 20; + //double eps = 1.0e-6; + if ((int)group_points_.size() < min_nmb) + return false; + + vector<pair<shared_ptr<ElementarySurface>, RevEngRegion*> > adj_elem, adj_elem_base; + getAdjacentElemInfo(adj_elem, adj_elem_base); + + shared_ptr<SplineSurface> spl = computeFreeform(group_points_, tol); + if (!spl.get()) + return false; +#ifdef DEBUG_EXTRACT + std::ofstream ofs("spl.g2"); + spl->writeStandardHeader(ofs); + spl->write(ofs); +#endif + + // Check accuracy + double maxd, avd; + int num2, num2_2; + vector<RevEngPoint*> inpt, outpt; + vector<pair<double, double> > dist_ang; + vector<double> parvals; + RevEngUtils::distToSurf(group_points_.begin(), group_points_.end(), + spl, tol, maxd, avd, num2, num2_2, inpt, outpt, + parvals, dist_ang, angtol); +#ifdef DEBUG_EXTRACT + std::ofstream ofd("in_out_spl.g2"); + ofd << "400 1 0 4 155 50 50 255" << std::endl; + ofd << inpt.size() << std::endl; + for (size_t kr=0; kr<inpt.size(); ++kr) + ofd << inpt[kr]->getPoint() << std::endl; + ofd << "400 1 0 4 50 155 50 255" << std::endl; + ofd << outpt.size() << std::endl; + for (size_t kr=0; kr<outpt.size(); ++kr) + ofd << outpt[kr]->getPoint() << std::endl; +#endif + + int num = (int)group_points_.size(); + double maxd_init, avd_init; + int num_init, num_init2; + getAccuracy(maxd_init, avd_init, num_init, num_init2); + if (associated_sf_.size() > 0 || (num2 > min_pt && num2 > num/2)) + { + extractOutPoints(dist_ang, tol, angtol, out_groups); + if (out_groups.size() > 0) + { + // Some points has been removed from the group. Redo surface + // generation + spl = computeFreeform(group_points_, tol); + if (!spl.get()) + return false; +#ifdef DEBUG_EXTRACT + std::ofstream ofs2("spl2.g2"); + spl->writeStandardHeader(ofs2); + spl->write(ofs2); +#endif + + num = (int)group_points_.size(); + dist_ang.clear(); + parvals.clear(); + inpt.clear(); + outpt.clear(); + RevEngUtils::distToSurf(group_points_.begin(), group_points_.end(), + spl, tol, maxd, avd, num2, num2_2, inpt, outpt, + parvals, dist_ang, angtol); +#ifdef DEBUG_EXTRACT + std::ofstream ofd2("in_out_spl2.g2"); + ofd2 << "400 1 0 4 155 50 50 255" << std::endl; + ofd2 << inpt.size() << std::endl; + for (size_t kr=0; kr<inpt.size(); ++kr) + ofd2 << inpt[kr]->getPoint() << std::endl; + ofd2 << "400 1 0 4 50 155 50 255" << std::endl; + ofd2 << outpt.size() << std::endl; + for (size_t kr=0; kr<outpt.size(); ++kr) + ofd2 << outpt[kr]->getPoint() << std::endl; +#endif + } + int stop_break_out = 1; + } + + int sf_flag = defineSfFlag(0, tol, num2, num2_2, avd, false); + if (sf_flag < ACCURACY_POOR) + { + bool OK = true; + if (associated_sf_.size() > 0) + { + // Check with current approximating surface + double acc_fac1 = 1.25; + double acc_fac2 = 0.75; + if (surfflag_ == ACCURACY_OK && sf_flag > surfflag_) + OK = false; + else if (prefer_elementary == ALWAYS_ELEM) + OK = false; + else if (prefer_elementary == PREFER_ELEM && + ((double)num2 < acc_fac1*num_init || + avd > acc_fac2*avd_init)) + OK = false; + else if (prefer_elementary == BEST_ACCURACY && + (num2 < num_init || avd > avd_init)) + OK = false; + } + + if (OK) + { + found = true; + for (size_t kh=0; kh<group_points_.size(); ++kh) + { + group_points_[kh]->setPar(Vector2D(parvals[2*kh],parvals[2*kh+1])); + group_points_[kh]->setSurfaceDist(dist_ang[kh].first, dist_ang[kh].second); + } + setAccuracy(maxd, avd, num2, num2_2); +#ifdef DEBUG + std::cout << "Spline. N1: " << num << ", N2: " << num2 << ", max: " << maxd << ", av: " << avd << std::endl; +#endif + shared_ptr<HedgeSurface> hedge(new HedgeSurface(spl, this)); + for (size_t kh=0; kh<associated_sf_.size(); ++kh) + prevsfs.push_back(associated_sf_[kh]); + setHedge(hedge.get()); + hedgesfs.push_back(hedge); + setSurfaceFlag(sf_flag); + } + } + int stop_break0 = 1; + return found; +} + + +//=========================================================================== + void RevEngRegion::removeAndUpdatePoints(vector<RevEngPoint*>& points) +//=========================================================================== + { + for (size_t ki=0; ki<points.size(); ++ki) + { + points[ki]->unsetRegion(); + points[ki]->unsetSurfInfo(); + vector<RevEngPoint*>::iterator it = std::find(group_points_.begin(), + group_points_.end(), + points[ki]); + if (it != group_points_.end()) + { + std::swap(*it, group_points_[group_points_.size()-1]); + group_points_.pop_back(); + //group_points_.erase(it); + } + } + } + +//=========================================================================== + void RevEngRegion::extractOutOfEdge(shared_ptr<CurveOnSurface>& cv, + vector<shared_ptr<CurveOnSurface> >& intcv, + double radius, double tol, double angtol, + vector<RevEngPoint*>& out_points) +//=========================================================================== + { + if (!hasSurface()) + return; // Points are not parameterized + shared_ptr<ParamCurve> pcv = cv->parameterCurve(); + if (!pcv.get()) + return; // Not possible to check configuration in parameter domain + + Point dir, norm0, norm; + if (pcv->isLinear(dir, angtol)) + norm0 = Point(-dir[1],dir[0]); + + // Check orientation of trimming curve + Point midp(0.5*(domain_[0]+domain_[1]), 0.5*(domain_[2]+domain_[3])); + double tpar1, dist1; + Point pclose1; + pcv->closestPoint(midp, pcv->startparam(), pcv->endparam(), tpar1, pclose1, dist1); + Point vec = pclose1 - midp; + if (norm0.dimension() > 0) + norm = norm0; + else + { + vector<Point> der(2); + pcv->point(der, tpar1, 1); + norm = Point(-der[1][1], der[1][0]); + } + int sgn = 0; + double dist2 = std::numeric_limits<double>::max(); + for (size_t ki=0; ki<intcv.size(); ++ki) + { + shared_ptr<ParamCurve> pcv2 = intcv[ki]->parameterCurve(); + if (!pcv2.get()) + continue; + double tpar2, dist2_2; + Point pclose2; + pcv2->closestPoint(midp, pcv2->startparam(), pcv2->endparam(), tpar2, pclose2, dist2_2); + if (dist2_2 < dist2) + { + dist2 = dist2_2; + if (dist2 < dist1) + sgn = (norm*vec < 0.0) ? 1 : -1; + else + sgn = (norm*vec < 0.0) ? -1 : 1; + } + } + + if (sgn == 0) + sgn = (norm*vec < 0.0) ? -1 : 1; + + // Check with point distribution + double mdist, cdist; + RevEngPoint *mclose = closestParPoint(midp, mdist); + RevEngPoint *cclose = closestParPoint(pclose1, cdist); + + vector<RevEngPoint*> remaining; + for (size_t ki=0; ki<group_points_.size(); ++ki) + { + Vector2D uv = group_points_[ki]->getPar(); + Point par(uv[0], uv[1]); + + // Check if the parameter point lies to the left of the parameter curve + double tpar, dist; + Point close; + pcv->closestPoint(par, pcv->startparam(), pcv->endparam(), tpar, + close, dist); + + if (norm0.dimension() > 0) + norm = norm0; + else + { + vector<Point> der(2); + pcv->point(der, tpar, 1); + norm = Point(-der[1][1], der[1][0]); + } + + vec = sgn*(close - par); + double ang = norm.angle(vec); + ang = std::min(ang, M_PI-ang); + if (norm*vec < 0.0 && ang <= angtol) + { + Vector3D xyz = group_points_[ki]->getPoint(); + Point pos(xyz[0], xyz[1], xyz[2]); + double dist3 = std::numeric_limits<double>::max(); + for (size_t kj=0; kj<intcv.size(); ++kj) + { + shared_ptr<ParamCurve> space = intcv[kj]->spaceCurve(); + if (!space.get()) + continue; + double tpar3, dist3_2; + Point close3; + space->closestPoint(pos, space->startparam(), space->endparam(), + tpar3, close3, dist3_2); + dist3 = std::min(dist3, dist3_2); + } + + if (fabs(dist3-radius) < tol) + out_points.push_back(group_points_[ki]); + else + remaining.push_back(group_points_[ki]); + } + else + remaining.push_back(group_points_[ki]); + } + + if (out_points.size() > 0 && remaining.size() > 0) + { + // If all points are outside, none will be extracted + std::swap(group_points_, remaining); + updateInfo(tol, angtol); + + shared_ptr<ParamSurface> surf = getSurface(0)->surface(); + bool cyllike = (surf->instanceType() == Class_Cylinder || + surf->instanceType() == Class_Cone); + int sf_flag = defineSfFlag(0, tol, num_inside_, num_inside2_, avdist_, cyllike); + setSurfaceFlag(sf_flag); + } + } + +//=========================================================================== + void RevEngRegion::extractOutOfEdge2(vector<shared_ptr<CurveOnSurface> >& intcv, + double tol, double angtol, + vector<RevEngPoint*>& out_points) +//=========================================================================== + { + if (!hasSurface()) + return; // Points are not parameterized + if (intcv.size() == 0) + return; + + // Check orientation of trimming curve + double midt = 0.5*(intcv[0]->startparam() + intcv[intcv.size()-1]->endparam()); + BoundingBox pbox(3); + int ix = -1; + for (size_t ki=0; ki<intcv.size(); ++ki) + { + if (intcv[ki]->startparam() <= midt && intcv[ki]->endparam() >= midt) + { + ix = (int)ki; + break; + } + } + if (ix < 0) + return; + + vector<Point> der(2); + intcv[ix]->point(der, midt, 1); + Point sfpar = intcv[ix]->faceParameter(midt); + Point sfnorm; + shared_ptr<ParamSurface> surf = intcv[ix]->underlyingSurface(); + surf->normal(sfnorm, sfpar[0], sfpar[1]); + Point vec = der[1].cross(sfnorm); + vec.normalize(); + double diag = bbox_.low().dist(bbox_.high()); + double dfac = 0.1; + Point pt1 = der[0] + dfac*diag*vec; + Point pt2 = der[0] - dfac*diag*vec; + double mdist1, mdist2; + RevEngPoint *rpt1, *rpt2; + rpt1 = closestPoint(pt1, mdist1); + rpt2 = closestPoint(pt2, mdist2); + int sgn = (mdist1 <= mdist2) ? -1 : 1; + + vector<RevEngPoint*> remaining; + for (size_t ki=0; ki<group_points_.size(); ++ki) + { + Vector3D xyz = group_points_[ki]->getPoint(); + Point pos(xyz[0], xyz[1], xyz[2]); + + // Check if the point lies to the left of the curve + double tpar; + Point close, norm; + double dist = std::numeric_limits<double>::max(); + int ix2 = -1; + for (size_t ki=0; ki<intcv.size(); ++ki) + { + double tpar2, dist2; + Point close2; + intcv[ki]->closestPoint(pos, intcv[ki]->startparam(), intcv[ki]->endparam(), tpar2, close2, dist2); + if (dist2 < dist) + { + tpar = tpar2; + dist = dist2; + close = close2; + ix2 = (int)ki; + } + } + + if (ix2 < 0) + remaining.push_back(group_points_[ki]); + else + { + vector<Point> der1(2); + intcv[ix2]->point(der1, tpar, 1); + Point sfpar2 = intcv[ix2]->faceParameter(tpar); + Point sfnorm2; + surf->normal(sfnorm2, sfpar2[0], sfpar2[1]); + Point vec2 = der[1].cross(sfnorm); + vector<Point> der2(2); + intcv[ix]->point(der2, tpar, 1); + Point vec3 = sgn*(der2[0] - pos); + double ang = der2[1].angle(vec3); + ang = fabs(0.5*M_PI - ang); + + if (vec2*vec3 < 0.0 && ang <= angtol) + out_points.push_back(group_points_[ki]); + else + remaining.push_back(group_points_[ki]); + } + } + + if (out_points.size() > 0 && remaining.size() > 0) + { + // If all points are outside, none will be extracted + std::swap(group_points_, remaining); + updateInfo(tol, angtol); + + shared_ptr<ParamSurface> surf = getSurface(0)->surface(); + bool cyllike = (surf->instanceType() == Class_Cylinder || + surf->instanceType() == Class_Cone); + int sf_flag = defineSfFlag(0, tol, num_inside_, num_inside2_, avdist_, cyllike); + setSurfaceFlag(sf_flag); + } + } + + //=========================================================================== + void RevEngRegion::extractOutPoints(vector<pair<double, double> >& dist_ang, + double tol, double angtol, + vector<vector<RevEngPoint*> >& out_groups) +//=========================================================================== + { + vector<RevEngPoint*> move; + for (size_t kr=0; kr<dist_ang.size(); ++kr) + { + if (dist_ang[kr].first > tol && + (associated_sf_.size() == 0 || + group_points_[kr]->getSurfaceDist() > tol)) + move.push_back(group_points_[kr]); + } + extractSpesPoints(move, out_groups, true); + if (out_groups.size() > 0) + updateInfo(tol, angtol); + } + +//=========================================================================== + void RevEngRegion::identifyAngPoints(vector<pair<double, double> >& dist_ang, + double tol, double disttol, + vector<RevEngPoint*>& ang_points) +//=========================================================================== + { + for (size_t kr=0; kr<dist_ang.size(); ++kr) + { + if (dist_ang[kr].second > tol && dist_ang[kr].first > disttol) + ang_points.push_back(group_points_[kr]); + } + } +//=========================================================================== + void RevEngRegion::identifyAngPoints(vector<pair<double, double> >& dist_ang, + double tol, double dtol, double dtol2, + vector<RevEngPoint*>& ang_points, + vector<RevEngPoint*>& remaining) +//=========================================================================== + { + for (size_t kr=0; kr<dist_ang.size(); ++kr) + { + if ((dist_ang[kr].second > tol && dist_ang[kr].first > dtol) || + dist_ang[kr].first > dtol2) + ang_points.push_back(group_points_[kr]); + else + remaining.push_back(group_points_[kr]); + } + } + +//=========================================================================== + void RevEngRegion::identifyDistPoints(vector<pair<double, double> >& dist_ang, + double tol, double maxd, double avd, + vector<RevEngPoint*>& dist_points) +//=========================================================================== + { + double tol2 = (avd > 0.9*tol) ? 3.0*tol : 2.0*tol; + for (size_t kr=0; kr<dist_ang.size(); ++kr) + { + if (dist_ang[kr].first > tol2) + dist_points.push_back(group_points_[kr]); + } + } + +//=========================================================================== +bool RevEngRegion::isConnected() +//=========================================================================== +{ + if (group_points_.size() == 0) + return false; + vector<RevEngPoint*> sub_group; + group_points_[0]->fetchConnected(this, (int)group_points_.size(), sub_group); + + for (size_t ki=0; ki<group_points_.size(); ++ki) + group_points_[ki]->unsetVisited(); +#ifdef DEBUG_CHECK + if (sub_group.size() < group_points_.size()) + { + vector<vector<RevEngPoint*> > conn_groups; + std::vector<RevEngPoint*> dummy; + connectedGroups(group_points_, conn_groups, false, dummy); + std::ofstream of("disconnect_groups.g2"); + for (size_t ki=0; ki<conn_groups.size(); ++ki) + { + of << "400 1 0 4 0 155 100 255" << std::endl; + of << conn_groups[ki].size() << std::endl; + for (size_t kj=0; kj<conn_groups[ki].size(); ++kj) + of << conn_groups[ki][kj]->getPoint() << std::endl; + } + } +#endif + + return (group_points_.size() == sub_group.size()); +} + +//=========================================================================== + void RevEngRegion::connectedGroups(vector<RevEngPoint*>& move, + vector<vector<RevEngPoint*> >& conn_groups, + bool outer, vector<RevEngPoint*>& inner) +//=========================================================================== + { + // Note: derived information in this group is not updated!! + shared_ptr<RevEngRegion> dummy_reg(new RevEngRegion(edge_class_type_)); + + for (size_t kr=0; kr<move.size(); ++kr) + move[kr]->setRegion(dummy_reg.get()); // Preliminary + + vector<vector<RevEngPoint*> > sep_move; + for (size_t kr=0; kr<move.size(); ++kr) + { + if (move[kr]->visited()) + continue; + vector<RevEngPoint*> curr_move; + move[kr]->fetchConnected(dummy_reg.get(), (int)move.size(), curr_move); + sep_move.push_back(curr_move); + } + + for (size_t kr=0; kr<move.size(); ++kr) + move[kr]->unsetVisited(); + +#ifdef DEBUG_EXTRACT + std::ofstream m1("move_group.g2"); + std::ofstream m2("not_move_group.g2"); +#endif + for (size_t kr=0; kr<sep_move.size(); ++kr) + { + size_t kh; + for (kh=0; kh<sep_move[kr].size(); ++kh) + { + vector<ftSamplePoint*> next = sep_move[kr][kh]->getNeighbours(); + size_t kh1; + for (kh1=0; kh1<next.size(); ++kh1) + { + RevEngPoint *pt = dynamic_cast<RevEngPoint*>(next[kh1]); + + RevEngRegion *reg = pt->region(); + if (reg != this && reg != dummy_reg.get()) + break; + } + if (kh1 < next.size()) + break; + } + if (kh < sep_move[kr].size() || (!outer)) + { + conn_groups.push_back(sep_move[kr]); +#ifdef DEBUG_EXTRACT + m1 << "400 1 0 0" << std::endl; + m1 << sep_move[kr].size() << std::endl; + for (size_t kh1=0; kh1<sep_move[kr].size(); ++kh1) + m1 << sep_move[kr][kh1]->getPoint() << std::endl; +#endif + } + else + { +#ifdef DEBUG_EXTRACT + m2 << "400 1 0 0" << std::endl; + m2 << sep_move[kr].size() << std::endl; + for (size_t kh1=0; kh1<sep_move[kr].size(); ++kh1) + m2 << sep_move[kr][kh1]->getPoint() << std::endl; +#endif + inner.insert(inner.end(), sep_move[kr].begin(), sep_move[kr].end()); + } + } + for (size_t kr=0; kr<move.size(); ++kr) + move[kr]->setRegion(this); + } + +//=========================================================================== + void RevEngRegion::extractSpesPoints(vector<RevEngPoint*>& move, + vector<vector<RevEngPoint*> >& out_groups, + bool outer) +//=========================================================================== + { + // Identify connected groups + std::vector<RevEngPoint*> dummy; + connectedGroups(move, out_groups, outer, dummy); + + // Extract group of out points from current group + for (size_t ki=0; ki<out_groups.size(); ++ki) + for (size_t kj=0; kj<out_groups[ki].size(); ++kj) + { + out_groups[ki][kj]->unsetRegion(); + out_groups[ki][kj]->addMove(); + vector<RevEngPoint*>::iterator it = std::find(group_points_.begin(), + group_points_.end(), + out_groups[ki][kj]); + if (it != group_points_.end()) + { + std::swap(*it, group_points_[group_points_.size()-1]); + group_points_.pop_back(); + //group_points_.erase(it); + } + } + + int stop_break = 1; + } + +//=========================================================================== +void RevEngRegion::removePoints(vector<RevEngPoint*>& remove) +//=========================================================================== + { + // Identify other points + std::vector<RevEngPoint*>::iterator end = group_points_.end(); + std::vector<RevEngPoint*>::iterator last = group_points_.end(); + --last; + for (size_t ki=0; ki<remove.size(); ++ki) + { + auto it = std::find(group_points_.begin(), end, remove[ki]); + if (it != end) + { + std::swap((*it), (*last)); + --last; + --end; + } + } + group_points_.erase(end, group_points_.end()); + } + +//=========================================================================== + void RevEngRegion::removeOtherPoints(vector<RevEngPoint*>& keep, + vector<HedgeSurface*>& prevsfs, + vector<vector<RevEngPoint*> >& out_groups) +//=========================================================================== + { + // Identify other points + vector<RevEngPoint*> remove; + for (size_t ki=0; ki<group_points_.size(); ++ki) + { + auto it = std::find(keep.begin(), keep.end(), group_points_[ki]); + if (it == keep.end()) + remove.push_back(group_points_[ki]); + } + + int num = (int)group_points_.size(); + if (remove.size() > 0) + { + extractSpesPoints(remove, out_groups, false); + updateInfo(); + } + + if (hasSurface() && (int)group_points_.size() < std::max(20, num/10)) + { + prevsfs.insert(prevsfs.end(), associated_sf_.begin(), associated_sf_.end()); + clearSurface(); + } + + for (size_t ki=0; ki<out_groups.size(); ++ki) + for (size_t kj=0; kj<out_groups[ki].size(); ++kj) + out_groups[ki][kj]->unsetRegion(); + + updateRegionAdjacency(); + int stop_break = 1; + } + +//=========================================================================== +shared_ptr<CurveOnSurface> +RevEngRegion::constParSfCv(shared_ptr<ParamSurface> surf, int dir, + double par, int bd, double t1, double t2) +//=========================================================================== +{ + double eps = std::max(0.0001*(t2-t1), 1.0e-4); + Point pdir = (dir == 0) ? Point(0.0, 1.0) : Point(1.0, 0.0); + vector<shared_ptr<ParamCurve> > cvs1 = surf->constParamCurves(par, (dir==1)); + if (!cvs1[0]->isBounded()) + { + shared_ptr<ElementaryCurve> elemcv = + dynamic_pointer_cast<ElementaryCurve,ParamCurve>(cvs1[0]); + elemcv->setParamBounds(t1, t2); + } + + if (cvs1[0]->startparam() < t1-eps || cvs1[0]->endparam() > t2+eps) + { + shared_ptr<ParamCurve> sub(cvs1[0]->subCurve(t1, t2)); + cvs1[0] = sub; + } + + Point ppos = (dir == 0) ? Point(par, 0.0) : Point(0.0, par); + shared_ptr<ElementaryCurve> pcrv(new Line(ppos, pdir)); + pcrv->setParamBounds(cvs1[0]->startparam(), cvs1[0]->endparam()); +#ifdef DEBUG_TRIM + Point sp1, sp2, ssp1, ssp2; + Point pp1, pp2; + cvs1[0]->point(sp1, cvs1[0]->startparam()); + cvs1[0]->point(sp2, cvs1[0]->endparam()); + pcrv->point(pp1, pcrv->startparam()); + pcrv->point(pp2, pcrv->endparam()); + surf->point(ssp1, pp1[0], pp1[1]); + surf->point(ssp2, pp2[0], pp2[1]); +#endif + shared_ptr<CurveOnSurface> sfcv(new CurveOnSurface(surf, pcrv, cvs1[0], false, + 3, dir+1, par, bd, true)); + return sfcv; + } +//=========================================================================== +bool RevEngRegion::trimSurface(double tol) +//=========================================================================== +{ + if (!hasSurface()) + return false; + + if (trim_edgs_.size() == 0) + return false; // Not ready for trimming +#ifdef DEBUG_TRIM + std::ofstream of1("par_edgs.g2"); + std::ofstream of1_2("space_edgs.g2"); + for (size_t ki=0; ki<trim_edgs_.size(); ++ki) + { + shared_ptr<CurveOnSurface> sfcv = + dynamic_pointer_cast<CurveOnSurface,ParamCurve>(trim_edgs_[ki]->geomCurve()); + if (!sfcv.get()) + continue; + shared_ptr<ParamCurve> pcurve = sfcv->parameterCurve(); + if (pcurve.get()) + SplineDebugUtils::writeSpaceParamCurve(pcurve, of1, 0.0); + shared_ptr<ParamCurve> scurve = sfcv->spaceCurve(); + if (scurve.get()) + { + scurve->writeStandardHeader(of1_2); + scurve->write(of1_2); + } + } +#endif + int status = 0; + HedgeSurface *hedge = getSurface(0); + shared_ptr<ParamSurface> surf = hedge->surface(); + RectDomain dom = surf->containingDomain(); + double dom2[4]; + dom2[0] = dom.umin(); + dom2[1] = dom.umax(); + dom2[2] = dom.vmin(); + dom2[3] = dom.vmax(); + bool closed_u = false, closed_v = false; + shared_ptr<ElementarySurface> elem = + dynamic_pointer_cast<ElementarySurface,ParamSurface>(surf); + if (elem.get()) + elem->isClosed(closed_u, closed_v); + else + { + shared_ptr<SplineSurface> splsf = + dynamic_pointer_cast<SplineSurface,ParamSurface>(surf); + if (splsf.get()) + { + int md1 = GeometryTools::analyzePeriodicityDerivs(*splsf, 0, 0, tol); + int md2 = GeometryTools::analyzePeriodicityDerivs(*splsf, 1, 0, tol); + closed_u = (md1 >= 0); + closed_v = (md2 >= 0); + } + } + + //double diag = bbox_.low().dist(bbox_.high()); + if (closed_u) + { + // Add seem along v-direction to the edge collection + double tdel = domain_[3] - domain_[2]; + double t1 = domain_[2] - 0.1*tdel; + double t2 = domain_[3] + 0.1*tdel; + shared_ptr<CurveOnSurface> seemcv1 = constParSfCv(surf, 0, dom2[0], 0, t1, t2); + shared_ptr<CurveOnSurface> seemcv2 = constParSfCv(surf, 0, dom2[1], 1, t1, t2); + shared_ptr<ftEdge> edg1(new ftEdge(hedge, seemcv1, seemcv1->startparam(), + seemcv1->endparam())); + shared_ptr<ftEdge> edg2(new ftEdge(hedge, seemcv2, seemcv2->startparam(), + seemcv2->endparam())); + int stat = 0; + edg1->connectTwin(edg2.get(), stat); + addTrimEdge(edg1); + addTrimEdge(edg2); + } + if (closed_v) + { + // Add seem along u-direction to the edge collection + double tdel = domain_[1] - domain_[0]; + double t1 = domain_[0] - 0.1*tdel; + double t2 = domain_[1] + 0.1*tdel; + shared_ptr<CurveOnSurface> seemcv1 = constParSfCv(surf, 1, dom2[2], 2, t1, t2); + shared_ptr<CurveOnSurface> seemcv2 = constParSfCv(surf, 1, dom2[3], 3, t1, t2); + shared_ptr<ftEdge> edg1(new ftEdge(hedge, seemcv1, seemcv1->startparam(), + seemcv1->endparam())); + shared_ptr<ftEdge> edg2(new ftEdge(hedge, seemcv2, seemcv2->startparam(), + seemcv2->endparam())); + int stat = 0; + edg1->connectTwin(edg2.get(), stat); + addTrimEdge(edg1); + addTrimEdge(edg2); + } + + bool do_bound = false; // Necessary to trim only if not all curves are boundary curves + vector<int> adjusted(trim_edgs_.size(), 0); + for (size_t ki=0; ki<trim_edgs_.size(); ++ki) + { + shared_ptr<CurveOnSurface> sfcv = + dynamic_pointer_cast<CurveOnSurface,ParamCurve>(trim_edgs_[ki]->geomCurve()); + if (!sfcv.get()) + continue; + if (sfcv->isConstantCurve()) + { + adaptOneEdge(trim_edgs_[ki], dom2); + bool same; + int bd = sfcv->whichBoundary(tol, same); +#ifdef DEBUG_TRIM + bool same_orient = sfcv->sameOrientation(); + bool same_trace = sfcv->sameTrace(tol); + bool same_cv = sfcv->sameCurve(tol); + if ((!same_orient) || (!same_trace) || (!same_cv)) + std::cout << "Surface curve mismatch " << ki << " " << sfcv << " " << same_orient << " " << same_trace << " " << same_cv << std::endl; + +#endif + if (bd < 0) + do_bound = true; + } + else + { + do_bound = true; + + double t1 = sfcv->startparam(); + double t2 = sfcv->endparam(); + + ftEdgeBase *twin0 = trim_edgs_[ki]->twin(); + if (twin0) + { + ftEdge *twin = twin0->geomEdge(); + shared_ptr<CurveOnSurface> sfcv2 = + dynamic_pointer_cast<CurveOnSurface,ParamCurve>(twin->geomCurve()); + double t3 = sfcv2->startparam(); + double t4 = sfcv2->endparam(); + if (sfcv2->isConstantCurve() && (t3 > t1 || t4 < t2)) + { + int mod = 0; + if (t3 > t1) + mod += 1; + if (t4 < t2) + mod += 2; + double tmin = std::max(t1, t3); + double tmax = std::min(t2, t4); + shared_ptr<CurveOnSurface> sub(sfcv->subCurve(tmin, tmax)); + shared_ptr<ftEdge> subedge(new ftEdge(sub, tmin, tmax)); + ftEdgeBase *twin = trim_edgs_[ki]->twin(); + trim_edgs_[ki]->disconnectTwin(); + subedge->connectTwin(twin, status); + trim_edgs_[ki] = subedge; + adjusted[ki] = mod; + } + int stop_break1 = 1; + } + } + } + + if (do_bound == false && trim_edgs_.size() != 4) + { + // Check if the parameter bound in the surface and in the existing trimming edges + // is constent + int stop_check = 1; + } + +#ifdef DEBUG_TRIM + std::ofstream of2("par_edgs2.g2"); + for (size_t ki=0; ki<trim_edgs_.size(); ++ki) + { + shared_ptr<CurveOnSurface> sfcv = + dynamic_pointer_cast<CurveOnSurface,ParamCurve>(trim_edgs_[ki]->geomCurve()); + if (!sfcv.get()) + continue; + shared_ptr<ParamCurve> pcurve = sfcv->parameterCurve(); + if (!pcurve.get()) + continue; + SplineDebugUtils::writeSpaceParamCurve(pcurve, of2, 0.0); + } +#endif + + if (do_bound) + { + bool OK = arrangeEdgeLoop(tol, adjusted); + if (!OK) + return false; + if (trim_edgs_.size() == 0) + return false; + + // Make bounded surface. + // First collect trimming curves + vector<shared_ptr<CurveOnSurface> > trim_cvs(trim_edgs_.size()); + // NB! Could be missing curves + bool missing_par_cvs = false; + for (size_t ki=0; ki<trim_edgs_.size(); ++ki) + { + shared_ptr<CurveOnSurface> tmp_sfcv = + dynamic_pointer_cast<CurveOnSurface,ParamCurve>(trim_edgs_[ki]->geomCurve()); + trim_cvs[ki] = shared_ptr<CurveOnSurface>(tmp_sfcv->clone()); // To avoid inconsistencies + // if two edges share the same curve in geometry space + if (!trim_cvs[ki].get()) + { + missing_par_cvs = true; + continue; // Should not happen + } + if (!trim_cvs[ki]->hasParameterCurve()) + missing_par_cvs = true; + } + + if (missing_par_cvs) + return false; // Will fail + + double eps = 1.0e-9; + vector<vector<shared_ptr<CurveOnSurface> > > trim_loops; + + // Check for separate and disconnected loops + shared_ptr<ParamCurve> pcv1 = trim_cvs[0]->parameterCurve(); + Point startpt = pcv1->point(pcv1->startparam()); + int first_ix = 0; + for (int ka=0; ka<(int)trim_cvs.size()-1; ++ka) + { + int kb = (ka+1)%(int)trim_cvs.size(); + shared_ptr<ParamCurve> pcv2 = trim_cvs[kb]->parameterCurve(); + Point end = pcv1->point(pcv1->endparam()); + Point start = pcv2->point(pcv2->startparam()); + double next_dd = end.dist(start); + double close_dd = end.dist(startpt); + if (close_dd <= next_dd+eps && close_dd <= tol) + { + vector<shared_ptr<CurveOnSurface> > curr_cvs(trim_cvs.begin()+first_ix, + (kb!=0) ? trim_cvs.begin()+kb : + trim_cvs.end()); + trim_loops.push_back(curr_cvs); + startpt = start; + first_ix = (kb!=0) ? kb : (int)trim_cvs.size(); + } + else if (next_dd > tol) + { + // Open segment. Dismiss + startpt = start; + first_ix = (kb!=0) ? kb : (int)trim_cvs.size(); + } + + // if (end.dist(start) > tol) + // { + // // Check for a closed loop + // if (end.dist(startpt) <= tol) + // { + // vector<shared_ptr<CurveOnSurface> > curr_cvs(trim_cvs.begin()+first_ix, + // (kb!=0) ? trim_cvs.begin()+kb : + // trim_cvs.end()); + // trim_loops.push_back(curr_cvs); + // startpt = start; + // first_ix = (kb!=0) ? kb : (int)trim_cvs.size(); + // } + // else + // { + // MESSAGE("RevEngRegion::trimSurface(): Obsolete code. Why do we end here?"); + + // } + // } + pcv1 = pcv2; + } + + if (first_ix < (int)trim_cvs.size()) + { + vector<shared_ptr<CurveOnSurface> > curr_cvs(trim_cvs.begin()+first_ix, + trim_cvs.end()); + trim_loops.push_back(curr_cvs); + } + +#ifdef DEBUG_TRIM + std::ofstream of3("par_edgs3.g2"); + std::ofstream of4("space_edgs3.g2"); + for (size_t ki=0; ki<trim_edgs_.size(); ++ki) + { + shared_ptr<CurveOnSurface> sfcv = + dynamic_pointer_cast<CurveOnSurface,ParamCurve>(trim_edgs_[ki]->geomCurve()); + if (!sfcv.get()) + continue; + shared_ptr<ParamCurve> pcurve = sfcv->parameterCurve(); + if (!pcurve.get()) + continue; + SplineDebugUtils::writeSpaceParamCurve(pcurve, of3, 0.0); + } + for (size_t ki=0; ki<trim_edgs_.size(); ++ki) + { + shared_ptr<CurveOnSurface> sfcv = + dynamic_pointer_cast<CurveOnSurface,ParamCurve>(trim_edgs_[ki]->geomCurve()); + if (!sfcv.get()) + continue; + shared_ptr<ParamCurve> scurve = sfcv->spaceCurve(); + scurve->writeStandardHeader(of4); + scurve->write(of4); + } + std::ofstream of3_2("par_edgs3_2.g2"); + std::ofstream of4_2("space_edgs3_2.g2"); + for (size_t ki=0; ki<trim_loops.size(); ++ki) + for (size_t kj=0; kj<trim_loops[ki].size(); ++kj) + { + shared_ptr<CurveOnSurface> sfcv = trim_loops[ki][kj]; + shared_ptr<ParamCurve> pcurve = sfcv->parameterCurve(); + if (pcurve.get()) + SplineDebugUtils::writeSpaceParamCurve(pcurve, of3_2, 0.0); + shared_ptr<ParamCurve> scurve = sfcv->spaceCurve(); + scurve->writeStandardHeader(of4_2); + scurve->write(of4_2); + } + +#endif + // Check orientation + vector<CurveLoop> loops; + if (trim_loops.size() == 1) + { + loops.push_back(CurveLoop(trim_loops[0], tol)); + bool is_CCW = LoopUtils::paramIsCCW(trim_loops[0], tol, tol); + if (!is_CCW) + { + loops[0].turnOrientation(); + // Must also turn edges + } + } + else + { + // Sort curves. Expects one outer loop and one or more inner loops + vector<Point> pt_on_cv(trim_loops.size()); + for (size_t ki=0; ki<trim_loops.size(); ++ki) + { + shared_ptr<ParamCurve> pcv = trim_loops[ki][0]->parameterCurve(); + pt_on_cv[ki] = pcv->point(0.5*(pcv->startparam()+pcv->endparam())); + } + + size_t ki; + for (ki=0; ki<trim_loops.size(); ++ki) + { + // Check if the point from all other loops lies inside current + vector<shared_ptr<ParamCurve> > par_cvs(trim_loops[ki].size()); + for (size_t kr=0; kr<trim_loops[ki].size(); ++kr) + { + par_cvs[kr] = trim_loops[ki][kr]->parameterCurve(); + } + + shared_ptr<CurveLoop> cvloop(new CurveLoop(par_cvs, tol, false)); + CurveBoundedDomain cvdom(cvloop); + size_t kj; + for (kj=0; kj<pt_on_cv.size(); ++kj) + { + if (kj == ki) + continue; + Vector2D ppos(pt_on_cv[kj][0], pt_on_cv[kj][1]); + bool inside = cvdom.isInDomain(ppos, tol); + if (!inside) + break; + } + if (kj == pt_on_cv.size()) + break; // Outer boundary found + } + if (ki < trim_loops.size()) + std::swap(trim_loops[0], trim_loops[ki]); + + loops.push_back(CurveLoop(trim_loops[0], tol)); + bool is_CCW = LoopUtils::paramIsCCW(trim_loops[0], tol, tol); + if (!is_CCW) + { + loops[0].turnOrientation(); + } + for (size_t kr=1; kr<trim_loops.size(); ++kr) + { + loops.push_back(CurveLoop(trim_loops[kr], tol)); + bool is_CCW = LoopUtils::paramIsCCW(trim_loops[kr], tol, tol); + if (is_CCW) + { + loops[kr].turnOrientation(); + } + } + } + + shared_ptr<BoundedSurface> bdsurf(new BoundedSurface(surf, loops)); +#ifdef DEBUG_TRIM + int valid_state; + bool valid = bdsurf->isValid(valid_state); + std::cout << "BoundedSurf is valid? " << valid << " " << valid_state << std::endl; + std::ofstream of5("bounded_surf.g2"); + bdsurf->writeStandardHeader(of5); + bdsurf->write(of5); +#endif + associated_sf_[0]->replaceSurf(bdsurf); + + // // Add existing trimming curves. Later + // for (size_t ki=0; ki<trim_edgs_.size(); ++ki) + // trim_edgs_[ki]->setFace(associated_sf_[0]); + // vector<shared_ptr<ftEdgeBase> > tmp_trim(trim_edgs_.begin(), trim_edgs_.end()); + // shared_ptr<Loop> edge_loop(new Loop(associated_sf_[0], tmp_trim, tol)); + // associated_sf_[0]->addOuterBoundaryLoop(edge_loop); + associated_sf_[0]->clearInitialEdges(); + (void)associated_sf_[0]->createInitialEdges(); +#ifdef DEBUG_TRIM + for (size_t ki=0; ki<trim_edgs_.size(); ++ki) + { + shared_ptr<CurveOnSurface> sfcv = + dynamic_pointer_cast<CurveOnSurface,ParamCurve>(trim_edgs_[ki]->geomCurve()); + Point startpt1 = sfcv->ParamCurve::point(sfcv->startparam()); + Point startpt2 = trim_edgs_[ki]->point(trim_edgs_[ki]->tMin()); + int stop_breakc = 1; + } +#endif + } // End do_bound + + return true; +} + +struct CloseCvInfo +{ + double par1_, par2_, dist_; + double par3_, par4_, dist2_; + + CloseCvInfo() + { + par1_ = par2_ = par3_ = par4_ = 0.0; + dist_ = dist2_ = -1.0; + } + + CloseCvInfo(double par1, double par2, double dist) + { + par1_ = par1; + par2_ = par2; + dist_ = dist; + par3_ = par4_ = 0.0; + dist2_ = -1.0; + } + + CloseCvInfo(double par1, double par2, double dist, + double par3, double par4, double dist2) + { + par1_ = par1; + par2_ = par2; + dist_ = dist; + par3_ = par3; + par4_ = par4; + dist2_ = dist2; + } +}; + +CloseCvInfo getCloseInfo(double tol, shared_ptr<ParamCurve>& pcurve1, int adjusted1, + shared_ptr<ParamCurve>& pcurve2, int adjusted2) +{ + Point close1, close2; + int status = 0; + double tmin1 = pcurve1->startparam(); + double tmax1 = pcurve1->endparam(); + double seed1 = 0.5*(tmin1 + tmax1); + Point pos1 = pcurve1->point(tmin1); + Point pos2 = pcurve1->point(tmax1); + double tmin2 = pcurve2->startparam(); + double tmax2 = pcurve2->endparam(); + double seed2 = 0.5*(tmin2 + tmax2); + Point pos3 = pcurve2->point(tmin2); + Point pos4 = pcurve2->point(tmax2); + double par1[9], par2[9]; + par1[0] = par1[1] = tmin1; + par1[2] = par1[3] = tmax1; + par1[5] = tmin1; + par1[6] = tmax1; + par2[7] = tmin2; + par2[8] = tmax2; + par2[0] = par2[2] = tmin2; + par2[1] = par2[3] = tmax2; + par1[4] = par1[7] = par1[8] = 0.5*(tmin1+tmax1); + par2[4] = par2[5] = par2[6] = 0.5*(tmin2+tmax2); + double dist[9]; + dist[0] = pos1.dist(pos3); + dist[1] = pos1.dist(pos4); + dist[2] = pos2.dist(pos3); + dist[3] = pos2.dist(pos4); + dist[4] = dist[5] = dist[6] = dist[7] = dist[8] = std::numeric_limits<double>::max(); + if (adjusted1 < 3 && adjusted2 < 3) + ClosestPoint::closestPtCurves2D(pcurve1.get(), pcurve2.get(), tol, + tmin1, tmax1, tmin2, tmax2, seed1, + seed2, 1, false, par1[4], par2[4], + dist[4], close1, close2, status); + if ((adjusted1 == 1 || adjusted1 == 3) && adjusted2 < 3) + pcurve2->closestPoint(pos1, tmin2, tmax2, par2[5], close2, dist[5]); + if ((adjusted2 == 1 || adjusted1 == 3) && adjusted2 < 3) + pcurve2->closestPoint(pos2, tmin2, tmax2, par2[6], close2, dist[6]); + if ((adjusted2 == 1 || adjusted2 == 3) && adjusted1 < 3) + pcurve1->closestPoint(pos3, tmin1, tmax1, par1[7], close1, dist[7]); + if ((adjusted2 == 2 || adjusted2 == 3) && adjusted1 < 3) + pcurve1->closestPoint(pos4, tmin1, tmax1, par1[8], close1, dist[8]); + + double eps = std::min(0.1*tol, 1.0e-4); + double eps2 = 1.0e-9; + for (int ka=4; ka<9; ++ka) + { + if (par1[ka]-tmin1 < eps2) + par1[ka] = tmin1; + if (tmax1-par1[ka] < eps2) + par1[ka] = tmax1; + if (par2[ka]-tmin2 < eps2) + par2[ka] = tmin2; + if (tmax2-par2[ka] < eps2) + par2[ka] = tmax2; + } + + if (adjusted2 == 1 || adjusted2 == 3) + { + if (par1[4] - tmin1 > eps2 && par1[4] - tmin1 < eps) + dist[4] = std::numeric_limits<double>::max(); + if (par1[7] - tmin1 > eps2 && par1[7] - tmin1 < eps) + dist[7] = std::numeric_limits<double>::max(); + if (par1[8] - tmin1 > eps2 && par1[8] - tmin1 < eps) + dist[8] = std::numeric_limits<double>::max(); + } + if (adjusted2 == 2 || adjusted2 == 3) + { + if (tmax1 - par1[4] > eps2 && tmax1 - par1[4] < eps) + dist[4] = std::numeric_limits<double>::max(); + if (tmax1 - par1[7] > eps2 && tmax1 - par1[7] < eps) + dist[7] = std::numeric_limits<double>::max(); + if (tmax1 - par1[8] > eps2 && tmax1 - par1[8] < eps) + dist[8] = std::numeric_limits<double>::max(); + } + + if (adjusted1 == 1 || adjusted1 == 3) + { + if (par2[4] - tmin2 > eps2 && par2[4] - tmin2 < eps) + dist[4] = std::numeric_limits<double>::max(); + if (par2[5] - tmin2 > eps2 && par2[5] - tmin2 < eps) + dist[5] = std::numeric_limits<double>::max(); + if (par2[6] - tmin2 > eps2 && par2[6] - tmin2 < eps) + dist[6] = std::numeric_limits<double>::max(); + } + if (adjusted1 == 2 || adjusted1 == 3) + { + if (tmax2 - par2[4] > eps2 && tmax2 - par2[4] < eps) + dist[4] = std::numeric_limits<double>::max(); + if (tmax2 - par2[5] > eps2 && tmax2 - par2[5] < eps) + dist[5] = std::numeric_limits<double>::max(); + if (tmax2 - par2[6] > eps2 && tmax2 - par2[6] < eps) + dist[6] = std::numeric_limits<double>::max(); + } + + + int ka, kb; + for (ka=0; ka<9; ++ka) + for (kb=ka+1; kb<9; ++kb) + { + // if ((kb < 4 && dist[kb] < dist[ka]) || (kb == 4 && dist[kb] < dist[ka]-tol)) + if (dist[kb] < dist[ka]) + { + std::swap(dist[ka], dist[kb]); + std::swap(par1[ka], par1[kb]); + std::swap(par2[ka], par2[kb]); + } + } + + if (fabs(par1[1] - par1[0]) < eps || fabs(par2[1]-par2[0]) < eps) + { + par1[1] = par1[2]; + par2[1] = par2[2]; + dist[1] = dist[2]; + } + CloseCvInfo curr_info(par1[0], par2[0], dist[0], par1[1], + par2[1], dist[1]); + return curr_info; + } + + +//=========================================================================== +bool RevEngRegion::arrangeEdgeLoop(double tol, vector<int>& adjusted) +//=========================================================================== +{ + vector<vector<CloseCvInfo> > info(trim_edgs_.size()); + vector<shared_ptr<CurveOnSurface> > sfcv(trim_edgs_.size()); + for (size_t ki=0; ki<trim_edgs_.size(); ++ki) + { + info[ki].resize(trim_edgs_.size()); + sfcv[ki] = + dynamic_pointer_cast<CurveOnSurface,ParamCurve>(trim_edgs_[ki]->geomCurve()); + } + + // Collect distance info + double tmin1, tmax1; + for (size_t ki=0; ki<trim_edgs_.size(); ++ki) + { + if (!sfcv[ki].get()) + continue; + shared_ptr<ParamCurve> pcurve1 = sfcv[ki]->parameterCurve(); + if (!pcurve1.get()) + return false; + + tmin1 = pcurve1->startparam(); + tmax1 = pcurve1->endparam(); + Point pos1 = pcurve1->point(tmin1); + Point pos2 = pcurve1->point(tmax1); + double dist0 = pos1.dist(pos2); + info[ki][ki] = CloseCvInfo(tmin1, tmax1, dist0); + for (size_t kj=ki+1; kj<trim_edgs_.size(); ++kj) + { + if (!sfcv[kj].get()) + continue; + shared_ptr<ParamCurve> pcurve2 = sfcv[kj]->parameterCurve(); + if (!pcurve2.get()) + return false; + + CloseCvInfo curr_info = getCloseInfo(tol, pcurve1, adjusted[ki], + pcurve2, adjusted[kj]); + info[ki][kj] = info[kj][ki] = curr_info; + } + } + + //#if 0 + // Identify gaps + double tol2 = 10.0*tol; + vector<pair<int, int> > adj_gap; + for (size_t ki=0; ki<info.size(); ++ki) + { + double ix1 = -1, ix2 = -1; + for (size_t kj=0; kj<info[ki].size(); ++kj) + { + // if (kj == ki) + // continue; + double dd = info[ki][kj].dist_; + if (dd <= tol2) + { + int num_small = 0; + for (size_t kr=0; kr<info[kj].size(); ++kr) + if (info[kj][kr].dist_ < dd) + num_small++; + if (num_small < 2) + { + if (ix1 < 0) + ix1 = (int)kj; + else if (ix2 < 0) + ix2 = (int)kj; + } + } + } + if (ix1 < 0 || (ix2 < 0 && ix1 != (int)ki)) + adj_gap.push_back(std::make_pair((int)ki, ix1)); + } + + vector<double> limit_par; + if (adj_gap.size() > 0) + { + for (size_t ki=0; ki<adj_gap.size(); ++ki) + { + // Fetch adjacent face + int cv_ix = adj_gap[ki].first; + ftEdgeBase* twin0 = trim_edgs_[cv_ix]->twin(); + if (!twin0) + continue; + ftEdge* twin = twin0->geomEdge(); + ftFaceBase *twin_face = twin->face(); + if (!twin_face) + continue; + HedgeSurface *adj_hedge = dynamic_cast<HedgeSurface*>(twin_face); + if (!adj_hedge) + continue; + RevEngRegion* other_reg = adj_hedge->getRegion(0); + vector<RevEngPoint*> edge_pts; + if (other_reg == this) + { + // Fetch points at seem + int dir; + double parval; + sfcv[cv_ix]->isConstantCurve(tol2, dir, parval); + bool udir = (dir == 1); // Should be sufficient + vector<RevEngPoint*> seam_pts1, seam_pts2; + extractPointsAtSeam(seam_pts1, seam_pts2, udir); + int ix = 1 - dir; + if (parval-domain_[2*ix] < domain_[2*ix+1]-parval) + edge_pts = seam_pts1; + else + edge_pts = seam_pts2; + int stop_b1 = 1; + } + else + { + vector<RevEngRegion*> others; + others.push_back(other_reg); + edge_pts = extractBdPoints(others); + int stop_b2 = 1; + } + + // Identify first and last point along edge + RevEngPoint *first_pt=0, *last_pt=0; + double t1, t2; + RevEngUtils::identifyEndPoints(edge_pts, sfcv[cv_ix], first_pt, t1, last_pt, t2); +#ifdef DEBUG_TRIM + if (t2 > t1) + { + std::ofstream ofpt("edge_ends.g2"); + if (first_pt) + { + ofpt << "400 1 0 4 100 100 55 255" << std::endl; + ofpt << "1" << std::endl; + ofpt << first_pt->getPar() << " 0.0" << std::endl; + } + if (last_pt) + { + ofpt << "400 1 0 4 100 100 55 255" << std::endl; + ofpt << "1" << std::endl; + ofpt << last_pt->getPar() << " 0.0" << std::endl; + } + } +#endif + if (t2 < t1) + std::swap(t1, t2); + if (adj_gap[ki].second < 0) + { + limit_par.push_back(t1); + limit_par.push_back(t2); + } + else + { + int ix2 = adj_gap[ki].second; + double t3 = (cv_ix < ix2) ? info[cv_ix][ix2].par1_ : info[cv_ix][ix2].par2_; + if (fabs(t3 - t1) < fabs(t3 - t2)) + limit_par.push_back(t2); + else limit_par.push_back(t1); + } + int stop_break0 = 1; + } + + // Sort gaps + vector<pair<pair<shared_ptr<CurveOnSurface>,double>, + pair<shared_ptr<CurveOnSurface>,double> > > gap_cv_bounds; + vector<bool> use_lower; + if (adj_gap.size() == 1 && limit_par.size() == 2) + { + int cv_ix = adj_gap[0].first; + gap_cv_bounds.push_back(make_pair(make_pair(sfcv[cv_ix],limit_par[0]), + make_pair(sfcv[cv_ix],limit_par[1]))); + use_lower.push_back(true); // Not used + } + else if (adj_gap.size() == 2 && limit_par.size() == 2) + { + int cv_ix1 = adj_gap[0].first; + int cv_ix2 = adj_gap[1].first; + double t3; + if (trim_edgs_[cv_ix1]->twin() == trim_edgs_[cv_ix2].get()) + { + // Seam curve. Unify end parameters + int ix2 = adj_gap[0].second; + t3 = (cv_ix1 < ix2) ? info[cv_ix1][ix2].par1_ : info[cv_ix1][ix2].par2_; + if (fabs(t3-limit_par[0]) < fabs(t3-limit_par[1])) + limit_par[0] = limit_par[1]; + else + limit_par[1] = limit_par[0]; + } + gap_cv_bounds.push_back(make_pair(make_pair(sfcv[cv_ix1],limit_par[0]), + make_pair(sfcv[cv_ix2],limit_par[1]))); + use_lower.push_back((limit_par[0]<t3)); + } + else + MESSAGE("RevEngRegion::arrangeEdgeLoop(): Gap configuration not implemented"); + + HedgeSurface *hedge = getSurface(0); + shared_ptr<ParamSurface> surf = hedge->surface(); + size_t num = trim_edgs_.size(); + for (size_t ki=0; ki<gap_cv_bounds.size(); ++ki) + { + shared_ptr<CurveOnSurface> sfcv1 = gap_cv_bounds[ki].first.first; + shared_ptr<CurveOnSurface> sfcv2 = gap_cv_bounds[ki].second.first; + int dir1, dir2; + double parval1, parval2; + sfcv1->isConstantCurve(tol, dir1, parval1); + sfcv2->isConstantCurve(tol, dir2, parval2); + + shared_ptr<ParamCurve> pcv1 = sfcv1->parameterCurve(); + shared_ptr<ParamCurve> pcv2 = sfcv2->parameterCurve(); + Point ppos1 = pcv1->point(gap_cv_bounds[ki].first.second); + Point ppos2 = pcv2->point(gap_cv_bounds[ki].second.second); + if (dir1 >= 0 && dir1 == dir2) + { + // Set surface limit based on parameter domain of points + int p_ix = 2 - dir1; + // if (std::min(fabs(ppos1[p_ix]-domain_[2*p_ix]), fabs(ppos1[p_ix]-domain_[2*p_ix])) < + // std::min(fabs(ppos1[p_ix]-domain_[2*p_ix+1]), fabs(ppos1[p_ix]-domain_[2*p_ix+1]))) + if (use_lower[ki]) + ppos1[p_ix] = ppos2[p_ix] = domain_[2*p_ix]; + else + ppos1[p_ix] = ppos2[p_ix] = domain_[2*p_ix+1]; + } + shared_ptr<SplineCurve> gap_par(new SplineCurve(ppos1, ppos2)); + shared_ptr<CurveOnSurface> gap_sfcv(new CurveOnSurface(surf, gap_par, true)); + gap_sfcv->ensureSpaceCrvExistence(tol); + shared_ptr<ftEdge> gap_edge(new ftEdge(hedge, gap_sfcv, gap_sfcv->startparam(), + gap_sfcv->endparam())); + sfcv.push_back(gap_sfcv); + trim_edgs_.push_back(gap_edge); + adjusted.push_back(true); + } + + if (sfcv.size() > num) + { + // Extend meeting information + info.resize(sfcv.size()); + for (size_t ki=0; ki<sfcv.size(); ++ki) + info[ki].resize(sfcv.size()); + + for (size_t ki=num; ki<trim_edgs_.size(); ++ki) + { + if (!sfcv[ki].get()) + continue; + shared_ptr<ParamCurve> pcurve1 = sfcv[ki]->parameterCurve(); + if (!pcurve1.get()) + continue; + + tmin1 = pcurve1->startparam(); + tmax1 = pcurve1->endparam(); + Point pos1 = pcurve1->point(tmin1); + Point pos2 = pcurve1->point(tmax1); + double dist0 = pos1.dist(pos2); + info[ki][ki] = CloseCvInfo(tmin1, tmax1, dist0); + for (size_t kj=0; kj<trim_edgs_.size(); ++kj) + { + if (kj >= num && kj <= ki) + continue; + if (!sfcv[kj].get()) + continue; + shared_ptr<ParamCurve> pcurve2 = sfcv[kj]->parameterCurve(); + if (!pcurve2.get()) + continue; + + CloseCvInfo curr_info = (ki > kj) ? + getCloseInfo(tol, pcurve2, adjusted[kj], pcurve1, adjusted[ki]) : + getCloseInfo(tol, pcurve1, adjusted[ki], pcurve2, adjusted[kj]);; + info[ki][kj] = info[kj][ki] = curr_info; + } + } + + } + int stop_break = 1; + } + //#endif + // Check if any curves must be reduced, and record previous and next curve + double eps = 1.0e-9; + int status = 0; + vector<pair<int, int> > seq(trim_edgs_.size()); + vector<pair<double, double> > param(trim_edgs_.size()); + for (size_t ki=0; ki<trim_edgs_.size(); ++ki) + { + int ix1=-1, ix2=-1; + double td1 = std::numeric_limits<double>::max(); + double td2 = std::numeric_limits<double>::max(); + double td0 = info[ki][ki].dist_; + double t1, t2; + t1 = t2 = 2.0*fabs(std::max(sfcv[ki]->startparam(), sfcv[ki]->endparam())); + double delta = 0.001*fabs(info[ki][ki].par2_ - info[ki][ki].par1_); + for (size_t kj=0; kj<info[ki].size(); ++kj) + { + if (ki == kj) + continue; + double dd = info[ki][kj].dist_; + double tp1 = (ki < kj) ? info[ki][kj].par1_ : info[ki][kj].par2_; + if (ix1 < 0 || dd < td1) + { + ix1 = (int)kj; + td1 = dd; + t1 = tp1; + } + } + + + for (size_t kj=0; kj<info[ki].size(); ++kj) + { + if (ki == kj) + continue; + double dd = info[ki][kj].dist_; + double dd2 = info[ki][kj].dist2_; + double tp1 = (ki < kj) ? info[ki][kj].par1_ : info[ki][kj].par2_; + double tp2 = (ki < kj) ? info[ki][kj].par3_ : info[ki][kj].par4_; + //double td12 = std::max(td1, td2); + if (ix2 < 0 || dd < td2) + { + if (fabs(tp1 - t1) > delta) + { + ix2 = (int)kj; + td2 = dd; + t2 = tp1; + } + else if ((ix2 < 0 || dd2 < td2) && fabs(tp2 - t1) > delta) + { + ix2 = (int)kj; + td2 = dd2; + t2 = tp2; + } + } + } + + + // if (ix1 < 0 || dd < td1) + // { + // if (ix1 < 0 || (ix2 >= 0 && td1 >= td2 && (!fabs(tp1 - t2) < eps))) + // { + // ix1 = (int)kj; + // td1 = dd; + // t1 = tp1; + // set1 = true; + // } + // else if (ix1 < 0 || (ix2 >= 0 && dd2 < td1 && + // td1 >= td2 && (!fabs(tp2 - t2) < eps))) + // { + // ix1 = (int)kj; + // td1 = dd2; + // t1 = tp2; + // set2 = true; + // } + // } + // if (ix2 < 0 || dd < td2) + // { + // if ((!set1) && ix1 >= 0 && td2 > td1 && (!fabs(tp1 - t1) < eps)) + // { + // ix2 = (int)kj; + // td2 = dd; + // t2 = tp1; + // } + // else if ((!set2) && ix1 >= 0 && dd2 < td2 && + // td2 > td1 && (!fabs(tp2 - t1) < eps)) + // { + // ix2 = (int)kj; + // td2 = dd2; + // t2 = tp2; + // } + // } + // if (ix1 < 0 || ((dd < td12-eps || + // (dd < td12 && fabs(t2-tp1) > eps)) && td2 <= td1)) + // { + // ix1 = (int)kj; + // td1 = dd; + // t1 = tp1; + // } + // else if (ix2 < 0 || ((dd < td12-eps || + // (dd < td12 && fabs(t1-tp1) > eps)) && td1 < td2)) + // { + // ix2 = (int)kj; + // td2 = dd; + // t2 = tp1; + // } + + // td12 = std::max(td1, td2); + // if (dd2 < 0.0) + // dd2 = td12; + // if (ix1 < 0 || ((dd2 < td12-eps || + // (dd2 < td12 && fabs(t2-tp2) > eps)) && td2 <= td1)) + // { + // ix1 = (int)kj; + // td1 = dd2; + // t1 = tp2; + // } + // else if (ix2 < 0 || ((dd2 < td12-eps || + // (dd2 < td12 && fabs(t1-tp2) > eps)) && td1 < td2)) + // { + // ix2 = (int)kj; + // td2 = dd2; + // t2 = (ki < kj) ? info[ki][kj].par3_ : info[ki][kj].par4_; + // } + //} + if (/*td1 > tol && td2 > tol &&*/ td0 < std::min(td1, td2)) + { + // Closed loop + ix1 = ix2 = (int)ki; + t1 = sfcv[ki]->startparam(); + t2 = sfcv[ki]->endparam(); + } + + if (t2 < t1) + { + std::swap(t1, t2); + std::swap(ix1, ix2); + } + seq[ki] = std::make_pair(ix1, ix2); + param[ki] = std::make_pair(t1, t2); + + if ((t1 > sfcv[ki]->startparam()+eps || t2 < sfcv[ki]->endparam()-eps) && t2 > t1) + { + if ((td1 > tol || td2 > tol) && + std::min(t1-sfcv[ki]->startparam(), sfcv[ki]->endparam()-t2) < tol) + { + // Extra testing + shared_ptr<ParamCurve> pcrv = sfcv[ki]->parameterCurve(); + double tpar = (t1-sfcv[ki]->startparam() > sfcv[ki]->endparam()-t2) ? t1 : t2; + double t3 = 0.75*tpar + 0.25*pcrv->startparam(); + double t4 = 0.75*tpar + 0.25*pcrv->endparam(); + Point ppar1 = pcrv->point(t3); + Point ppar2 = pcrv->point(t4); + Point close1(std::max(domain_[0], std::min(domain_[1], ppar1[0])), + std::max(domain_[2], std::min(domain_[3], ppar1[1]))); + Point close2(std::max(domain_[0], std::min(domain_[1], ppar2[0])), + std::max(domain_[2], std::min(domain_[3], ppar2[1]))); + double d1 = ppar1.dist(close1); + double d2 = ppar2.dist(close2); + if (tpar == t1 && d1<d2) + { + t2 = sfcv[ki]->startparam(); + std::swap(t1, t2); + std::swap(ix1, ix2); + seq[ki] = std::make_pair(ix1, ix2); + } + else if (tpar == t2 && d2<d1) + { + t1 = sfcv[ki]->endparam(); + std::swap(t1, t2); + std::swap(ix1, ix2); + seq[ki] = std::make_pair(ix1, ix2); + } + int stop_d = 1; + } + shared_ptr<CurveOnSurface> sub(sfcv[ki]->subCurve(t1, t2)); + shared_ptr<ftEdge> subedge(new ftEdge(sub, t1, t2)); + ftEdgeBase *twin = trim_edgs_[ki]->twin(); + if (twin) + { + trim_edgs_[ki]->disconnectTwin(); + subedge->connectTwin(twin, status); + } + trim_edgs_[ki] = subedge; + } + } + + // Could be necessary to remove extra entrances of closed edges + + vector<int> seq_ix; + vector<bool> turn; + seq_ix.push_back(0); + turn.push_back(false); + vector<size_t> start_ix; + start_ix.push_back(0); + while (seq_ix.size() < trim_edgs_.size()) + { + size_t ix = seq_ix.size() - 1; + for (size_t ki=ix; ki<seq_ix.size(); ++ki) + { + // Select next curve + int ix1 = seq[seq_ix[ki]].first; + int ix2 = seq[seq_ix[ki]].second; + double t1 = param[seq_ix[ki]].first; + double t2 = param[seq_ix[ki]].second; + Point pt1 = sfcv[seq_ix[ki]]->parameterCurve()->point(t1); + Point pt2 = sfcv[seq_ix[ki]]->parameterCurve()->point(t2); + for (size_t kr=0; kr<seq_ix.size(); ++kr) + { + if (seq_ix[kr] == ix1) + ix1 = -1; + if (seq_ix[kr] == ix2) + ix2 = -1; + } + + if (ix1 >= 0 && turn[ki]) + { + seq_ix.push_back(ix1); + Point pt3 = sfcv[ix1]->parameterCurve()->point(param[ix1].first); + Point pt4 = sfcv[ix1]->parameterCurve()->point(param[ix1].second); + if (pt1.dist(pt3) > pt1.dist(pt4)) + turn.push_back(true); + else + turn.push_back(false); + } + else if (ix2 >= 0 && (!turn[ki])) + { + seq_ix.push_back(ix2); + Point pt3 = sfcv[ix2]->parameterCurve()->point(param[ix2].first); + Point pt4 = sfcv[ix2]->parameterCurve()->point(param[ix2].second); + if (pt2.dist(pt3) > pt2.dist(pt4)) + turn.push_back(true); + else + turn.push_back(false); + } + } + + for (size_t ki=seq_ix.size()-1; ki<seq_ix.size(); ++ki) + { + // Select previous curve + int ix1 = seq[seq_ix[ix]].first; + int ix2 = seq[seq_ix[ix]].second; + double t1 = param[seq_ix[ix]].first; + double t2 = param[seq_ix[ix]].second; + Point pt1 = sfcv[seq_ix[ix]]->parameterCurve()->point(t1); + Point pt2 = sfcv[seq_ix[ix]]->parameterCurve()->point(t2); + for (size_t kr=0; kr<seq_ix.size(); ++kr) + { + if (seq_ix[kr] == ix1) + ix1 = -1; + if (seq_ix[kr] == ix2) + ix2 = -1; + } + + if (ix1 >= 0 && (!turn[ix])) + { + seq_ix.insert(seq_ix.begin()+ix, ix1); + Point pt3 = sfcv[ix1]->parameterCurve()->point(param[ix1].first); + Point pt4 = sfcv[ix1]->parameterCurve()->point(param[ix1].second); + if (pt1.dist(pt4) < pt1.dist(pt3)) + turn.insert(turn.begin()+ix, false); + else + turn.insert(turn.begin()+ix, true); + } + else if (ix2 >= 0 && turn[ix]) + { + seq_ix.push_back(ix2); + Point pt3 = sfcv[ix2]->parameterCurve()->point(param[ix2].first); + Point pt4 = sfcv[ix2]->parameterCurve()->point(param[ix2].second); + if (pt2.dist(pt3) > pt2.dist(pt4)) + turn.insert(turn.begin()+ix, false); + else + turn.insert(turn.begin()+ix, true); + } + } + // Select unused edge + size_t kr, kh; + for (kr=0; kr<trim_edgs_.size(); ++kr) + { + for (kh=0; kh<seq_ix.size(); ++kh) + if (seq_ix[kh] == (int)kr) + break; + + if (kh == seq_ix.size()) + { + start_ix.push_back(seq_ix.size()); + seq_ix.push_back((int)kr); + turn.push_back(false); + break; + } + } + } + start_ix.push_back(seq_ix.size()); + // vector<int> seq_ix(trim_edgs_.size(), -1); + // vector<bool> turn(trim_edgs_.size(), false); + // seq_ix[0] = 0; + // for (size_t ki=0; ki<trim_edgs_.size()-1; ++ki) + // { + // // Select next curve + // int ix1 = seq[seq_ix[ki]].first; + // int ix2 = seq[seq_ix[ki]].second; + // double t1 = param[seq_ix[ki]].first; //(seq_ix[ki] < ix1) ? info[seq_ix[ki]][ix1].par1_ : info[seq_ix[ki]][ix1].par2_; + // double t2 = param[seq_ix[ki]].second; //(seq_ix[ki] < ix2) ? info[seq_ix[ki]][ix2].par1_ : info[seq_ix[ki]][ix2].par2_; + // Point pt1 = sfcv[ki]->ParamCurve::point(t1); + // Point pt2 = sfcv[ki]->ParamCurve::point(t2); + // for (size_t kr=0; kr<ki; ++kr) + // { + // if (seq_ix[kr] == ix1) + // ix1 = -1; + // if (seq_ix[kr] == ix2) + // ix2 = -1; + // } + // if (ix1 != ix2 && ix1 >= 0 && ((turn[ki] && t1<t2) || ((!turn[ki]) && t2<t1))) + // { + // seq_ix[ki+1] = ix1; + // //double t3 = (seq_ix[ki] < ix1) ? info[seq_ix[ki]][ix1].par2_ : info[seq_ix[ki]][ix1].par1_; + // //if (fabs(sfcv[ix1]->endparam()-t3) < fabs(t3-sfcv[ix1]->startparam())) + // Point pt3 = sfcv[ix1]->ParamCurve::point(sfcv[ix1]->startparam()); + // Point pt4 = sfcv[ix1]->ParamCurve::point(sfcv[ix1]->endparam()); + // if (pt1.dist(pt4)+pt2.dist(pt3) < pt1.dist(pt3)+pt2.dist(pt4)) + // turn[ki+1] = true; + // } + // else if (ix1 != ix2 && ix2 >= 0) + // { + // seq_ix[ki+1] = ix2; + // //double t3 = (seq_ix[ki] < ix2) ? info[seq_ix[ki]][ix2].par2_ : info[seq_ix[ki]][ix2].par1_; + // //if (fabs(sfcv[ix2]->endparam()-t2) < fabs(t3-sfcv[ix2]->startparam())) + // Point pt3 = sfcv[ix2]->ParamCurve::point(sfcv[ix2]->startparam()); + // Point pt4 = sfcv[ix2]->ParamCurve::point(sfcv[ix2]->endparam()); + // if (pt1.dist(pt4)+pt2.dist(pt3) < pt1.dist(pt3)+pt2.dist(pt4)) + // turn[ki+1] = true; + // } + // else + // { + // // Select unused edge + // size_t kr, kh; + // for (kr=0; kr<trim_edgs_.size(); ++kr) + // { + // for (kh=0; kh<=ki; ++kh) + // if (seq_ix[kh] == (int)kr) + // break; + // if (kh > ki) + // { + // seq_ix[ki+1] = (int)kr; + // turn[ki+1] = false; + // break; + // } + // } + // } + // } + + vector<shared_ptr<ftEdge> > tmp_edgs(trim_edgs_.size()); + for (size_t ki=0; ki<trim_edgs_.size(); ++ki) + tmp_edgs[ki] = trim_edgs_[seq_ix[ki]]; + std::swap(trim_edgs_, tmp_edgs); + + for (size_t ki=0; ki<trim_edgs_.size(); ++ki) + if (turn[ki]) + trim_edgs_[ki]->reverseGeomCurve(); + +#ifdef DEBUG_TRIM + std::ofstream of0("trim_edgs_arrange0.g2"); + for (size_t ki=0; ki<trim_edgs_.size(); ++ki) + { + shared_ptr<CurveOnSurface> sfcv = + dynamic_pointer_cast<CurveOnSurface,ParamCurve>(trim_edgs_[ki]->geomCurve()); + if (!sfcv.get()) + continue; + shared_ptr<ParamCurve> space = sfcv->spaceCurve(); + if (!space.get()) + continue; + space->writeStandardHeader(of0); + space->write(of0); + Point startpt = space->point(space->startparam()); + of0 << "400 1 0 4 255 0 0 255" << std::endl; + of0 << "1" << std::endl; + of0 << startpt << std::endl; + } +#endif + + HedgeSurface *hedge = getSurface(0); + shared_ptr<ParamSurface> surf = hedge->surface(); + double lenfac = 0.6; + double tol4 = 4.0*tol; + for (size_t ki=1; ki<start_ix.size(); ++ki) + { + size_t kj, kr; + for (kj=start_ix[ki-1]; kj<start_ix[ki]; ++kj) + { + kr = (start_ix[ki]-start_ix[ki-1] == 1) ? kj : + ((kj == start_ix[ki]-1) ? start_ix[ki-1] : kj+1); + + // Check distance between adjacent curve segments + Point pt1 = trim_edgs_[kj]->point(trim_edgs_[kj]->tMax()); + Point pt2 = trim_edgs_[kr]->point(trim_edgs_[kr]->tMin()); + double glen = pt1.dist(pt2); + if (glen > tol) + { + // Define missing edge + shared_ptr<CurveOnSurface> sfcv1 = + dynamic_pointer_cast<CurveOnSurface,ParamCurve>(trim_edgs_[kj]->geomCurve()); + shared_ptr<CurveOnSurface> sfcv2 = + dynamic_pointer_cast<CurveOnSurface,ParamCurve>(trim_edgs_[kr]->geomCurve()); + if ((!sfcv1.get()) || (!sfcv2.get())) + continue; + + double clen = sfcv1->estimatedCurveLength(); + if (kj == kr && (!trim_edgs_[kj]->twin())) + { + // Single curve + if (glen > lenfac*clen) + { + // Remove trimming curve + trim_edgs_.erase(trim_edgs_.begin()+kj); + for (size_t kh=ki+1; kh<start_ix.size(); ++kh) + start_ix[kh]--; + start_ix.erase(start_ix.begin()+ki); + --ki; + break; + } + + } + + if (clen - glen < tol4) + continue; // Don't duplicate an almost straight curve + + shared_ptr<ParamCurve> pcv1 = sfcv1->parameterCurve(); + shared_ptr<ParamCurve> pcv2 = sfcv2->parameterCurve(); + if ((!pcv1.get()) || (!pcv2.get())) + continue; + + Point ppos1 = pcv1->point(pcv1->endparam()); + Point ppos2 = pcv2->point(pcv2->startparam()); + if (ppos1.dist(ppos2) < eps) + continue; + shared_ptr<SplineCurve> gap_par(new SplineCurve(ppos1, ppos2)); + shared_ptr<CurveOnSurface> gap_sfcv(new CurveOnSurface(surf, + gap_par, + true)); + gap_sfcv->ensureSpaceCrvExistence(tol); + shared_ptr<ftEdge> gap_edge(new ftEdge(hedge, gap_sfcv, + gap_sfcv->startparam(), + gap_sfcv->endparam())); + trim_edgs_.insert(trim_edgs_.begin()+kr, gap_edge); + + for (size_t kh=ki; kh<start_ix.size(); ++kh) + start_ix[kh]++; + ++kj; + } + } + } + +#ifdef DEBUG_TRIM + std::ofstream of1("trim_edgs_arrange.g2"); + for (size_t ki=0; ki<trim_edgs_.size(); ++ki) + { + shared_ptr<CurveOnSurface> sfcv = + dynamic_pointer_cast<CurveOnSurface,ParamCurve>(trim_edgs_[ki]->geomCurve()); + if (!sfcv.get()) + continue; + shared_ptr<ParamCurve> space = sfcv->spaceCurve(); + if (!space.get()) + continue; + space->writeStandardHeader(of1); + space->write(of1); + Point startpt = space->point(space->startparam()); + of1 << "400 1 0 4 255 0 0 255" << std::endl; + of1 << "1" << std::endl; + of1 << startpt << std::endl; + } +#endif + + int stop_break = 1; + return true; +} + +//=========================================================================== +void RevEngRegion::extractPointsAtSeam(vector<RevEngPoint*>& seam_pts1, + vector<RevEngPoint*>& seam_pts2, bool along_udir) +//=========================================================================== +{ + // Investigate only the points close to the domain boundary + int p_ix = along_udir ? 0 : 1; + double start = domain_[2*p_ix]; + double end = start + 0.1*(domain_[2*p_ix+1] - domain_[2*p_ix]); + double end2 = domain_[2*p_ix+1]; + double start2 = end2 - 0.1*(domain_[2*p_ix+1] - domain_[2*p_ix]); + std::set<RevEngPoint*> tmp_pts2; + for (size_t ki=0; ki<group_points_.size(); ++ki) + { + Vector2D uv = group_points_[ki]->getPar(); + if (uv[p_ix] >= start && uv[p_ix] <= end) + { + bool found = false; + vector<ftSamplePoint*> next = group_points_[ki]->getNeighbours(); + for (size_t kj=0; kj<next.size(); ++kj) + { + RevEngPoint *curr = dynamic_cast<RevEngPoint*>(next[kj]); + Vector2D uv2 = curr->getPar(); + if (uv2[p_ix] >= start2 && uv2[p_ix] <= end2) + { + tmp_pts2.insert(curr); + found = true; + } + } + if (found) + seam_pts1.push_back(group_points_[ki]); + } + } + if (tmp_pts2.size() > 0) + { + vector<RevEngPoint*> tmp2_pts2(tmp_pts2.begin(), tmp_pts2.end()); + seam_pts2 = tmp2_pts2; + } +} + +//=========================================================================== +void RevEngRegion::getAdjCandMerge(vector<RevEngRegion*>& adj_surf, + vector<RevEngRegion*>& adj_nosurf) +//=========================================================================== +{ + vector<RevEngRegion*> adj_reg; + adj_reg.insert(adj_reg.end(), adjacent_regions_.begin(), adjacent_regions_.end()); + for (size_t ki=0; ki<adj_reg.size(); ++ki) + for (size_t kj=ki+1; kj<adj_reg.size(); ++kj) + if (adj_reg[kj]->numPoints() > adj_reg[ki]->numPoints()) + std::swap(adj_reg[ki], adj_reg[kj]); + for (size_t ki=0; ki<adj_reg.size(); ++ki) + + { + if (adj_reg[ki]->prev_region_ && adj_reg[ki]->prev_region_ == this) + continue; + if (commonRevEdge(adj_reg[ki]) || adj_reg[ki]->hasAssociatedBlend() || + adj_reg[ki]->hasBlendEdge()) + continue; + + if (adj_reg[ki]->hasSurface()) + { + // Check compatibility (todo) + adj_surf.push_back(adj_reg[ki]); + } + else + { + // Check compatibility (todo) + adj_nosurf.push_back(adj_reg[ki]); + } + } +} + +//=========================================================================== +bool RevEngRegion::commonRevEdge(RevEngRegion *other) +//=========================================================================== +{ + vector<RevEngEdge*> other_edgs = other->getAllRevEdges(); + for (size_t ki=0; ki<rev_edges_.size(); ++ki) + for (size_t kj=0; kj<other_edgs.size(); ++kj) + if (rev_edges_[ki] == other_edgs[kj]) + return true; + + return false; +} + +//=========================================================================== +bool RevEngRegion::commonTrimEdge(RevEngRegion *other) +//=========================================================================== +{ + for (size_t ki=0; ki<trim_edgs_.size(); ++ki) + { + ftEdgeBase *twin0 = trim_edgs_[ki]->twin(); + if (!twin0) + continue; + ftEdge *twin = twin0->geomEdge(); + ftFaceBase *face0 = twin->face(); + if (!face0) + continue; + HedgeSurface *hedge = dynamic_cast<HedgeSurface*>(face0); + if (!hedge) + continue; + RevEngRegion *reg = hedge->getRegion(0); + if (reg == other) + return true; + } + return false; +} + +//=========================================================================== +void RevEngRegion::adaptEdges() +//=========================================================================== +{ + if (associated_sf_.size() > 0) + { + RectDomain dom = associated_sf_[0]->surface()->containingDomain(); + double dom2[4]; + dom2[0] = dom.umin(); + dom2[1] = dom.umax(); + dom2[2] = dom.vmin(); + dom2[3] = dom.vmax(); + for (size_t ki=0; ki<trim_edgs_.size(); ++ki) + { + adaptOneEdge(trim_edgs_[ki], dom2); + } + } +} + +//=========================================================================== +void RevEngRegion::adaptOneEdge(shared_ptr<ftEdge>& edge, double dom[4]) +//=========================================================================== +{ + int status = 0; + double eps = 1.0e-9; + shared_ptr<CurveOnSurface> sfcv = + dynamic_pointer_cast<CurveOnSurface,ParamCurve>(edge->geomCurve()); + if (!sfcv.get()) + return; + if (sfcv->isConstantCurve()) + { + int dir, bd; + double val; + bool orient; + sfcv->getConstantCurveInfo(dir, val, bd, orient); + shared_ptr<ParamCurve> pcurve = sfcv->parameterCurve(); + if (pcurve.get()) + { + double t1 = pcurve->startparam(); + double t2 = pcurve->endparam(); + Point pt1 = pcurve->point(t1); + Point pt2 = pcurve->point(t2); + double tpar, dist; + Point close; + int ix = (dir == 1) ? 1 : 0; + double tmax = std::max(pt1[ix], pt2[ix]); + double tmin = std::min(pt1[ix], pt2[ix]); + if (tmax > dom[2*ix+1]+eps) + { + Point pos; + pos = (ix == 0) ? Point(dom[2*ix+1], val) : Point(val, dom[2*ix+1]); + pcurve->closestPoint(pos, t1, t2, tpar, close, dist); + t2 = tpar; + } + if (tmin < dom[2*ix]-eps) + { + Point pos; + pos = (ix == 0) ? Point(dom[2*ix], val) : Point(val, dom[2*ix]); + pcurve->closestPoint(pos, t1, t2, tpar, close, dist); + t1 = tpar; + } + + if (t1 > pcurve->startparam() || t2 < pcurve->endparam()) + { + shared_ptr<CurveOnSurface> sub(sfcv->subCurve(t1, t2)); + shared_ptr<ftEdge> subedge(new ftEdge(edge->face(), sub, t1, t2)); + ftEdgeBase *twin = edge->twin(); + edge->disconnectTwin(); + subedge->connectTwin(twin, status); + edge = subedge; + } + } + else + MESSAGE("adaptCurve, missing parameter curve"); + } + else + MESSAGE("adaptCurve for non-constant trimming curves is not implemented"); +} + +//=========================================================================== +void RevEngRegion::getAdjacentBlends(vector<RevEngRegion*>& adj_blends) +//=========================================================================== +{ + for (auto it=adjacent_regions_.begin(); it!= adjacent_regions_.end(); ++it) + { + if ((*it)->hasBlendEdge()) + adj_blends.push_back(*it); + } +} + +//=========================================================================== +shared_ptr<SplineSurface> RevEngRegion::updateFreeform(vector<RevEngPoint*>& points, + double tol) +//=========================================================================== +{ + shared_ptr<SplineSurface> dummy; + if (associated_sf_.size() == 0) + return dummy; + + shared_ptr<ParamSurface> surf0 = associated_sf_[0]->surface(); + shared_ptr<SplineSurface> surf = + dynamic_pointer_cast<SplineSurface,ParamSurface>(surf0); + if (!surf.get()) + return dummy; + + vector<double> data, param; + for (size_t ki=0; ki<points.size(); ++ki) + { + Vector3D xyz = points[ki]->getPoint(); + Vector2D uv = points[ki]->getPar(); + data.insert(data.end(), xyz.begin(), xyz.end()); + param.insert(param.end(), uv.begin(), uv.end()); + } + + int dim = surf->dimension(); + ApproxSurf approx(surf, data, param, dim, tol); + //ApproxSurf approx(surf3, data, param, dim, tol, 0, false, true, 0, true); + approx.setMBA(true); + approx.setFixBoundary(false); + int max_iter = 1; + double maxd, avd; + int num_out; + shared_ptr<SplineSurface> surf2; + try { + surf2 = approx.getApproxSurf(maxd, avd, num_out, max_iter); + } + catch (...) + { + std::cout << "Surface update failed" << std::endl; + } + + return surf2; +} + + +//=========================================================================== +shared_ptr<SplineSurface> RevEngRegion::computeFreeform(vector<RevEngPoint*>& points, + double tol) +//=========================================================================== +{ +// Parameterize + vector<double> data, param; + int inner1=0, inner2=0; + + // Compute PCA axes + double lambda[3]; + Point eigen1, eigen2, eigen3; + getPCA(lambda, eigen1, eigen2, eigen3); + + //bool usebasesf = false; + bool done = false; + bool close1 = false, close2 = false; + if (associated_sf_.size() > 0) + { + done = parameterizeOnSurf(group_points_, + associated_sf_[0]->surface(), data, + param, inner1, inner2, close1, close2); + } + if (!done && basesf_.get() && avdist_base_ <= 5.0*tol) + { + done = parameterizeOnSurf(group_points_, basesf_, data, param, + inner1, inner2, close1, close2); + } + if (!done) + { + // Parameterize on plane + RevEngUtils::parameterizeWithPlane(points, bbox_, eigen1, + eigen2, data, param); + } +#ifdef DEBUG_EXTRACT + std::ofstream ofpar("parpoints.g2"); + int nmbpar = (int)param.size()/2; + ofpar << "400 1 0 0" << std::endl; + ofpar << nmbpar << std::endl; + for (int ka=0; ka<nmbpar; ++ka) + ofpar << param[2*ka] << " " << param[2*ka+1] << " 0.0" << std::endl; +#endif + + vector<double> param2; + double umin, umax, vmin, vmax; + bool repar = reparameterize(param, param2, umin, umax, vmin, vmax); + //std::cout << "repar: " << repar << std::endl; + if (repar) + { + vector<double> p_edg1, p_edg2; + for (size_t ki=0; ki<points.size(); ++ki) + { + vector<ftSamplePoint*> next = points[ki]->getNeighbours(); + for (size_t kj=0; kj<next.size(); ++kj) + { + RevEngPoint *pt = dynamic_cast<RevEngPoint*>(next[kj]); + if (pt->region() != this) + continue; + std::vector<RevEngPoint*>::iterator it = std::find(points.begin(), + points.end(), pt); + if (it != points.end()) + { + int ix = (int)(it - points.begin()); + p_edg1.push_back(param[2*ki]); + p_edg1.push_back(param[2*ki+1]); + p_edg2.push_back(param2[2*ki]); + p_edg2.push_back(param2[2*ki+1]); + p_edg1.push_back(param[2*ix]); + p_edg1.push_back(param[2*ix+1]); + p_edg2.push_back(param2[2*ix]); + p_edg2.push_back(param2[2*ix+1]); + } + } + } + +#ifdef DEBUG_EXTRACT + std::ofstream ofe1("par_edgs1.g2"); + std::ofstream ofe2("par_edgs2.g2"); + ofe1 << "410 1 0 4 255 0 0 255" << std::endl; + ofe2 << "410 1 0 4 255 0 0 255" << std::endl; + ofe1 << p_edg1.size()/4 << std::endl; + ofe2 << p_edg2.size()/4 << std::endl; + for (size_t ki=0; ki<p_edg1.size(); ki+=4) + { + ofe1 << p_edg1[ki] << " " << p_edg1[ki+1] << " 0.0 " << p_edg1[ki+2]; + ofe1 << " " << p_edg1[ki+3] << " 0.0" << std::endl; + ofe2 << p_edg2[ki] << " " << p_edg2[ki+1] << " 0.0 " << p_edg2[ki+2]; + ofe2 << " " << p_edg2[ki+3] << " 0.0" << std::endl; + } +#endif + + double plenfac = 5.0; + if (umax - umin > plenfac*(vmax - vmin)) + { + if (inner1 <= inner2) + inner1 = inner2 + 1; + } + else if (vmax - vmin > plenfac*(umax - umin)) + { + if (inner2 <= inner1) + inner2 = inner1 + 1; + } + std::swap(param, param2); + } + + // Extend with extra points in corners far from the point cloud + //size_t nmb_prev_extend = param.size(); + if ((!close1) && (!close2)) + { + try { + extendInCorner(data, param, umin, umax, vmin, vmax); + } + catch (...) + { + std::cout << "Corner extend failed" << std::endl; + } + } + + // Approximate + double maxd, avd; + int num_out; + int max_iter = (associated_sf_.size() > 0) ? 3 : 6; //2; + int dim = bbox_.low().dimension(); + int order = 4; + shared_ptr<SplineSurface> surf; + double del = 0.01; + vector<double> parvals; + try { + surf = RevEngUtils::surfApprox(data, dim, param, order, order, + order+inner1, order+inner2, + close1, close2, max_iter, + tol, maxd, avd, num_out, parvals, del); + } + catch (...) + { +#ifdef DEBUG_EXTRACT + std::cout << "Surface approximation failed" << std::endl; +#endif + } + +#ifdef DEBUG_EXTRACT + if (surf.get()) + { + std::ofstream of("spline_approx.g2"); + surf->writeStandardHeader(of); + surf->write(of); + } + else + int no_surf = 1; +#endif + + return surf; +} + +int compare_u_par(const void* el1, const void* el2) +{ + if (((double*)el1)[0] < ((double*)el2)[0]) + return -1; + else if (((double*)el1)[0] > ((double*)el2)[0]) + return 1; + else + return 0; +} + +int compare_v_par(const void* el1, const void* el2) +{ + if (((double*)el1)[1] < ((double*)el2)[1]) + return -1; + else if (((double*)el1)[1] > ((double*)el2)[1]) + return 1; + else + return 0; +} + +//=========================================================================== +bool RevEngRegion::reparameterize(vector<double>& param, vector<double>& param2, + double& umin, double& umax, double& vmin, double& vmax) +//=========================================================================== +{ + // Define raster + int nmb_div = 15; + vector<vector<int> > raster; + vector<double> param_copy(param.begin(), param.end()); // Raster definition + // changes sequence of parameter points + defineRaster(param_copy, nmb_div, raster, umin, umax, vmin, vmax); + int div2 = (int)raster.size(); + if (div2 == 0) + return false; + int div1 = (int)raster[0].size(); + double udel = (umax - umin)/(double)(div1); + double vdel = (vmax - vmin)/(double)(div2); + + // Count number of empty cells + int nmb_zero = 0; + for (int kb=0; kb<div2; ++kb) + for (int ka=0; ka<div1; ++ka) + if (raster[kb][ka] == 0) + ++nmb_zero; + + if (nmb_zero < (int)(0.5*div1*div2)) + return false; + + // Identify points on edges + double eps = 1.0e-10; + vector<double> edge_pts; + for (size_t kr=0; kr<param.size(); kr+=2) + { + if (param[kr]-umin < eps || umax-param[kr] < eps) + { + edge_pts.push_back((param[kr]-umin < eps) ? 0.0 : (double)div1); + edge_pts.push_back(0.5*(int)(2*(param[kr+1]-vmin)/vdel)); + } + if (param[kr+1]-vmin < eps || vmax-param[kr+1] < eps) + { + edge_pts.push_back(0.5*(int)(2*(param[kr]-umin)/udel)); + edge_pts.push_back((param[kr+1]-vmin < eps) ? 0.0 : (double)div2); + } + } + + // Find candidates for endpoints of a mid curve through the paramaeter points + vector<Point> cand_par; + vector<double> wd; + int i1, i2, i3, i4, ix, kc; + for (kc=0, ix=0; kc<2; ++kc, ix=div2-1) + for (i1=i2=0; i1<div1; i1=i2) + { + for (; i1<div1; ++i1) + if (raster[ix][i1] > 0) + break; + for (i2=i1; i2<div1; ++i2) + if (raster[ix][i2] == 0) + break; + if (i2 > i1) + { + size_t kr; + for (kr=0; kr<edge_pts.size(); kr+=2) + { + if (((kc == 0 && edge_pts[kr+1] == 0) || + (kc == 1 && edge_pts[kr+1] == div2)) && + (edge_pts[kr] >= i1 && edge_pts[kr] <= i2)) + break; + } + + if (kr < edge_pts.size()) + { + Point currpar(2); + currpar[0] = edge_pts[kr]; //0.5*(i1+i2); + currpar[1] = (kc == 0) ? 0 : (double)div2; + cand_par.push_back(currpar); + wd.push_back(0.5*udel*(i2-i1)); + } + } + } + + for (kc=0, ix=0; kc<2; ++kc, ix=div1-1) + for (i1=i2=0; i1<div2; i1=i2) + { + for (; i1<div2; ++i1) + if (raster[i1][ix] > 0) + break; + for (i2=i1; i2<div2; ++i2) + if (raster[i2][ix] == 0) + break; + if (i2 > i1) + { + size_t kr; + for (kr=0; kr<edge_pts.size(); kr+=2) + { + if (((kc == 0 && edge_pts[kr] == 0) || + (kc == 1 && edge_pts[kr] == div1)) && + (edge_pts[kr+1] >= i1 && edge_pts[kr+1] <= i2)) + break; + } + + if (kr < edge_pts.size()) + { + Point currpar(2); + currpar[0] = (kc == 0) ? 0 : (double)div1; + currpar[1] = edge_pts[kr+1]; //0.5*(i1+i2); + cand_par.push_back(currpar); + wd.push_back(0.5*vdel*(i2-i1)); + } + } + } + + if (cand_par.size() < 2) + return false; + + // Decide on endpoints + int ix1=-1, ix2=-1; + double maxd = std::numeric_limits<double>::lowest(); + for (size_t kr=0; kr<cand_par.size(); ++kr) + for (size_t kh=kr+1; kh<cand_par.size(); ++kh) + { + double dd = cand_par[kr].dist(cand_par[kh]); + dd -= (wd[kr] + wd[kh]); + if (dd > maxd) + { + ix1 = (int)kr; + ix2 = (int)kh; + maxd = dd; + } + } + + // Compute points along a sceleton in the parameter point cloud + double curr1[2], curr2[2]; + double wd1, wd2; + vector<double> ptpar; + vector<double> width; + ptpar.push_back(cand_par[ix1][0]); + ptpar.push_back(cand_par[ix1][1]); + width.push_back(wd[ix1]); + + Point prev; + int sgn1=0, sgn2=0; + bool loop = false; + for (kc=0; kc<(int)ptpar.size(); kc+=2) + { +#ifdef DEBUG_REPAR + std::ofstream ofc("midpol.g2"); + ofc << "410 1 0 4 0 0 0 255" << std::endl; + ofc << ptpar.size()/2 << std::endl; + ofc << umin+udel*ptpar[0] << " " << vmin+vdel*ptpar[1] << " 0.0" << std::endl; + for (size_t kr=2; kr<ptpar.size(); kr+=2) + { + ofc << umin+udel*ptpar[kr] << " " << vmin+vdel*ptpar[kr+1] << " 0.0" << std::endl; + ofc << umin+udel*ptpar[kr] << " " << vmin+vdel*ptpar[kr+1] << " 0.0" << std::endl; + } + ofc << umin+udel*cand_par[ix2][0] << " " << vmin+vdel*cand_par[ix2][1] << " 0.0" << std::endl; +#endif + curr1[0] = curr2[0] = ptpar[kc]; + curr1[1] = curr2[1] = ptpar[kc+1]; + if (sgn1 == 0 || curr1[0] == prev[0]) + sgn1 = (cand_par[ix2][0] > curr1[0]) ? 1 : -1; + if (sgn2 == 0 || curr2[1] == prev[1]) + sgn2 = (cand_par[ix2][1] > curr2[1]) ? 1 : -1; + double fac1 = (curr1[0] == 0.0) ? 0.5 : 1.0; + double fac2 = (curr2[1] == 0.0) ? 0.5 : 1.0; + curr1[0] += fac1*sgn1; + curr2[1] += fac2*sgn2; + prev = Point(ptpar[kc], ptpar[kc+1]); + if (prev.dist(cand_par[ix2]) <= 1.0) + break; + curr1[0] = std::min(curr1[0], div1-0.5); + curr1[1] = std::min(curr1[1], div2-0.5); + curr2[0] = std::min(curr2[0], div1-0.5); + curr2[1] = std::min(curr2[1], div2-0.5); + curr1[0] = std::max(curr1[0], 0.0); + curr1[1] = std::max(curr1[1], 0.0); + curr2[0] = std::max(curr2[0], 0.0); + curr2[1] = std::max(curr2[1], 0.0); + + // Extent with constant first parameter direction + getParExtent(curr1, 0, raster, i1, i2); + curr1[1] = 0.5*(double)(i1+i2+1); + wd1 = 0.5*(i1 - i2); + + // Constant second parameter direction + getParExtent(curr2, 1, raster, i3, i4); + curr2[0] = 0.5*(double)(i3+i4+1); + wd2 = 0.5*(i3 - i4); + + // Select continuation + Point lastpar(ptpar[ptpar.size()-2], ptpar[ptpar.size()-1]); + Point c1(curr1[0], curr1[1]); + Point c2(curr2[0], curr2[1]); + if (i1-i2 < i3-i4 || c2.dist(lastpar) < eps) + { + ptpar.push_back(curr1[0]); + ptpar.push_back(curr1[1]); + width.push_back(udel*wd1); + lastpar = c1; + } + else + { + ptpar.push_back(curr2[0]); + ptpar.push_back(curr2[1]); + width.push_back(vdel*wd2); + lastpar = c2; + } + + // Check for loops + for (size_t kh=2; kh<ptpar.size()-2; kh+=2) + { + Point currpar(ptpar[kh], ptpar[kh+1]); + if (currpar.dist(lastpar) < eps) + { + loop = true; + break; + } + } + if (loop) + break; + + int stop_break0 = 1; + } + if (loop) + return false; + + Point last(ptpar[ptpar.size()-2], ptpar[ptpar.size()-1]); + if (last.dist(cand_par[ix2]) > 0.0) + { + ptpar.push_back(cand_par[ix2][0]); + ptpar.push_back(cand_par[ix2][1]); + width.push_back(wd[ix2]); + } + + if (ptpar.size() <= 2) + return false; + + // Translate to real coordinates + vector<double> ptpar2(ptpar.size()); + for (size_t kr=0; kr<ptpar.size(); kr+=2) + { + ptpar2[kr] = umin+udel*ptpar[kr]; + ptpar2[kr+1] = vmin+vdel*ptpar[kr+1]; + } + + // Extend + double npar1[2], npar2[2]; + for (int ka=0; ka<2; ++ka) + { + npar1[ka] = ptpar2[ka] - 0.1*(ptpar2[2+ka]-ptpar2[ka]); + npar2[ka] = ptpar2[ptpar2.size()-2+ka] + 0.1*(ptpar2[ptpar2.size()-2+ka]- + ptpar2[ptpar2.size()-4+ka]); + } + ptpar2.insert(ptpar2.begin(), &npar1[0], &npar1[0]+2); + ptpar2.insert(ptpar2.end(), &npar2[0], &npar2[0]+2); + width.insert(width.begin(), width[0]); + width.push_back(width[width.size()-1]); + + +#ifdef DEBUG_REPAR + std::ofstream ofp("parpt.g2"); + ofp << "400 1 0 4 200 55 0 255" << std::endl; + ofp << ptpar2.size()/2 << std::endl; + for (size_t kr=0; kr<ptpar2.size(); kr+=2) + ofp << ptpar2[kr] << " " << ptpar2[kr+1] << " 0.0" << std::endl; +#endif + + // Define "mid" curve + vector<double> par2(ptpar2.size()/2); + par2[0] = 0.0; + for (size_t kr=2; kr<ptpar2.size(); kr+=2) + { + double dd = Utils::distance_squared(&ptpar2[kr-2], &ptpar2[kr], &ptpar2[kr]); + par2[kr/2] = par2[(kr-2)/2] + sqrt(dd); + } + + int in = 4, ik = 4; + int dim = 2; + double tol = 0.1; + ApproxCurve approx(ptpar2, par2, dim, tol, in, ik); + + double maxdist, avdist; + shared_ptr<SplineCurve> midcv = approx.getApproxCurve(maxdist, avdist, 1); + + ApproxCurve approx2(width, par2, 1, tol, in, ik); + + double maxdistw, avdistw; + shared_ptr<SplineCurve> widthcv = approx2.getApproxCurve(maxdistw, avdistw, 1); + +#ifdef DEBUG_REPAR + std::ofstream ofmid("midcv.g2"); + midcv->writeStandardHeader(ofmid); + midcv->write(ofmid); +#endif + + double avw = 0.0; + for (size_t kr=0; kr<width.size(); ++kr) + avw += width[kr]; + avw /= (double)width.size(); + + param2.resize(param.size()); + double tmin = midcv->startparam(); + double tmax = midcv->endparam(); + for (size_t kr=0; kr<param.size(); kr+=2) + { + Point currpar(param[kr], param[kr+1]); + double tpar, dist; + Point close; + midcv->closestPoint(currpar, tmin, tmax, tpar, close, dist); + + vector<Point> der(2); + midcv->point(der, tpar, 1); + Point vec = close - currpar; + Point vec2(-vec[1], vec[0]); + //double tmp = fabs(der[1]*vec); + // if (tmp > 1.0e-6) + // std::cout << "inner: " << tmp << std::endl; + if (vec2*der[1] < 0.0) + dist *= -1.0; + Point wdt = widthcv->ParamCurve::point(tpar); + //dist *= (avw/wdt[0]); + param2[kr] = tpar; + param2[kr+1] = dist; + int stop_break0 = 1; + } + +#ifdef DEBUG_REPAR + std::ofstream ofpar2("parpoints_repar.g2"); + int nmbpar = (int)param2.size()/2; + ofpar2 << "400 1 0 0" << std::endl; + ofpar2 << nmbpar << std::endl; + for (int ka=0; ka<nmbpar; ++ka) + ofpar2 << param2[2*ka] << " " << param2[2*ka+1] << " 0.0" << std::endl; +#endif + + vector<vector<int> > raster2; + double umin2, umax2, vmin2, vmax2; + vector<double> param2_copy(param2.begin(), param2.end()); // Raster definition + // changes sequence of parameter points + defineRaster(param2_copy, nmb_div, raster2, umin2, umax2, vmin2, vmax2); + + // Count number of empty cells + int nmb_zero2 = 0; + for (size_t kr=0; kr<raster2.size(); ++kr) + for (size_t kh=0; kh<raster2[kr].size(); ++kh) + if (raster2[kr][kh] == 0) + ++nmb_zero2; + + if (nmb_zero2 >= nmb_zero) + return false; + + umin = umin2; + umax = umax2; + vmin = vmin2; + vmax = vmax2; + return true; +} + +//=========================================================================== +void RevEngRegion::getParExtent(double curr[2], int pdir, vector<vector<int> >& raster, + int& i1, int& i2) +//=========================================================================== +{ + int div = (pdir == 0) ? (int)raster.size() : (int)raster[0].size(); + int j1 = (int)curr[pdir]; + int pdir2 = 1 - pdir; + + for (i1=(int)curr[pdir2]; i1<div; ++i1) + { + int r1 = (pdir == 0) ? raster[i1][j1] : raster[j1][i1]; + if (r1 > 0) + break; + } + if (i1 == div) + i1=(int)curr[pdir2]; + for (; i1<div; ++i1) + { + int r1 = (pdir == 0) ? raster[i1][j1] : raster[j1][i1]; + if (r1 == 0) + break; + } + for (i2=(int)curr[pdir2]; i2>=0; --i2) + { + int r1 = (pdir == 0) ? raster[i2][j1] : raster[j1][i2]; + if (r1 > 0) + break; + } + if (i2 < 0) + i2=(int)curr[pdir2]; + for (; i2>=0; --i2) + { + int r1 = (pdir == 0) ? raster[i2][j1] : raster[j1][i2]; + if (r1 == 0) + break; + } + } + + +//=========================================================================== +void RevEngRegion::defineRaster(vector<double>& param, int nmb_div, + vector<vector<int> >& raster, double& umin, + double& umax, double& vmin, double& vmax) +//=========================================================================== +{ + umin = std::numeric_limits<double>::max(); + umax = std::numeric_limits<double>::lowest(); + vmin = std::numeric_limits<double>::max(); + vmax = std::numeric_limits<double>::lowest(); + for (size_t kr=0; kr<param.size(); kr+=2) + { + umin = std::min(umin, param[kr]); + umax = std::max(umax, param[kr]); + vmin = std::min(vmin, param[kr+1]); + vmax = std::max(vmax, param[kr+1]); + } + + int nm = nmb_div*nmb_div; + double dom = (umax-umin)*(vmax-vmin); + double c1 = std::pow((double)nm/dom, 1.0/2.0); + int div1, div2; + div1 = (int)(c1*(umax-umin)); + ++div1; + div2 = (int)(c1*(vmax-vmin)); + ++div2; + double udel = (umax - umin)/(double)(div1); + double vdel = (vmax - vmin)/(double)(div2); + +#ifdef DEBUG_REPAR + std::ofstream of("division_lines.g2"); + of << "410 1 0 4 255 0 0 255" << std::endl; + of << div1+div2+2 << std::endl; + for (int ki=0; ki<=div1; ++ki) + { + Point p1(umin+ki*udel, vmin, 0.0); + Point p2(umin+ki*udel, vmax, 0.0); + of << p1 << " " << p2 << std::endl; + } + for (int ki=0; ki<=div2; ++ki) + { + Point p1(umin, vmin+ki*vdel, 0.0); + Point p2(umax, vmin+ki*vdel, 0.0); + of << p1 << " " << p2 << std::endl; + } +#endif + + raster.resize(div2); + for (size_t kr=0; kr<raster.size(); ++kr) + { + raster[kr].resize(div1, 0); + } + + int nmb_pts = (int)param.size()/2; + qsort(¶m[0], nmb_pts, 2*sizeof(double), compare_v_par); + int pp0, pp1; + int ka, kb; + double upar, vpar; + for (vpar=vmin+vdel, pp0=0, kb=0; kb<div2; ++kb, vpar+=vdel) + { + for (pp1=pp0; pp1<2*nmb_pts && param[pp1+1]<=vpar; pp1+=2); + qsort(¶m[pp0], (pp1-pp0)/2, 2*sizeof(double), compare_u_par); + + int pp2, pp3; + for (upar=umin+udel, pp2=pp0, ka=0; ka<div1; ++ka, upar+=udel) + { + for (pp3=pp2; pp3<pp1 && param[pp3]<=upar; pp3+=2); + raster[kb][ka] = (pp3-pp2)/2; + pp2 = pp3; + } + pp0 = pp1; + } +} + +//=========================================================================== +void RevEngRegion::extendInCorner(vector<double>& data, vector<double>& param, + double umin, double umax, double vmin, double vmax) +//=========================================================================== +{ + Point corner[4]; + corner[0] = Point(umin, vmin); + corner[1] = Point(umax, vmin); + corner[2] = Point(umin, vmax); + corner[3] = Point(umax, vmax); + double cdist[4]; + cdist[0] = cdist[1] = cdist[2] = cdist[3] = std::numeric_limits<double>::max(); + for (size_t kr=0; kr<param.size(); kr+=2) + { + Point currpar(param[kr], param[kr+1]); + for (int ka=0; ka<4; ++ka) + { + double dd = corner[ka].dist(currpar); + cdist[ka] = std::min(cdist[ka], dd); + } + } + + int div = 15; + double minc = std::min((umax-umin)/(double)div, (vmax-vmin)/(double)div); + vector<double> corner_data; + vector<double> corner_par; + int min_nmb = 20; + for (int ka=0; ka<4; ++ka) + { + if (cdist[ka] > minc) + { + // Estimate corner point + // Collect points in the vicinity of the corner + vector<double> data2; + vector<double> param2; + double umin2 = std::numeric_limits<double>::max(); + double umax2 = std::numeric_limits<double>::lowest(); + double vmin2 = std::numeric_limits<double>::max(); + double vmax2 = std::numeric_limits<double>::lowest(); + double lim = 1.1*cdist[ka]; //2.0 + for (size_t kr=0; kr<param.size()/2; ++kr) + { + Point currpar(param[2*kr], param[2*kr+1]); + if (currpar.dist(corner[ka]) < lim) + { + data2.insert(data2.end(), data.begin()+3*kr, data.begin()+3*(kr+1)); + param2.insert(param2.end(), param.begin()+2*kr, param.begin()+2*(kr+1)); + umin2 = std::min(umin2, param[2*kr]); + umax2 = std::max(umax2, param[2*kr]); + vmin2 = std::min(vmin2, param[2*kr+1]); + vmax2 = std::max(vmax2, param[2*kr+1]); + } + } + + while ((int)data2.size()/3 < min_nmb) + { + data2.clear(); + param2.clear(); + lim += 0.5*cdist[ka]; + for (size_t kr=0; kr<param.size()/2; ++kr) + { + Point currpar(param[2*kr], param[2*kr+1]); + if (currpar.dist(corner[ka]) < lim) + { + data2.insert(data2.end(), data.begin()+3*kr, data.begin()+3*(kr+1)); + param2.insert(param2.end(), param.begin()+2*kr, param.begin()+2*(kr+1)); + umin2 = std::min(umin2, param[2*kr]); + umax2 = std::max(umax2, param[2*kr]); + vmin2 = std::min(vmin2, param[2*kr+1]); + vmax2 = std::max(vmax2, param[2*kr+1]); + } + } + } + + // Approximate sub cloud with a planar surface + umin2 = std::min(umin2, corner[ka][0]); + umax2 = std::max(umax2, corner[ka][0]); + vmin2 = std::min(vmin2, corner[ka][1]); + vmax2 = std::max(vmax2, corner[ka][1]); + umin2 -= 0.1*(umax2 - umin2); + umax2 += 0.1*(umax2 - umin2); + vmin2 -= 0.1*(vmax2 - vmin2); + vmax2 += 0.1*(vmax2 - vmin2); + + shared_ptr<SplineSurface> plane = + RevEngUtils::surfApprox(data2, 3, param2, 2, 2, 2, 2, umin, umax, + vmin, vmax); + Point pos = plane->ParamSurface::point(corner[ka][0], corner[ka][1]); + corner_data.insert(corner_data.end(), pos.begin(), pos.end()); + corner_par.insert(corner_par.end(), corner[ka].begin(), corner[ka].end()); + } + } + + if (corner_data.size() > 0) + { + data.insert(data.end(), corner_data.begin(), corner_data.end()); + param.insert(param.end(), corner_par.begin(), corner_par.end()); + +#ifdef DEBUG_REPAR + std::ofstream of("added_corners.g2"); + for (size_t ki=0; ki<corner_data.size()/3; ++ki) + { + of << "400 1 0 4 255 0 0 255" << std::endl; + of << "1" << std::endl; + for (int ka=0; ka<3; ++ka) + of << corner_data[3*ki+ka] << " "; + of << std::endl; + } +#endif + } +} + + +//=========================================================================== +bool RevEngRegion::parameterizeOnSurf(shared_ptr<ParamSurface> surf, + vector<double>& data, vector<double>& param, + int& inner1, int& inner2, bool& close1, bool& close2) +//=========================================================================== +{ + return parameterizeOnSurf(group_points_, surf, data, param, inner1, inner2, + close1, close2); +} + +//=========================================================================== +bool RevEngRegion::parameterizeOnSurf(vector<RevEngPoint*>& points, + shared_ptr<ParamSurface> surf, + vector<double>& data, vector<double>& param, + int& inner1, int& inner2, bool& close1, bool& close2) +//=========================================================================== +{ + ClassType classtype = surf->instanceType(); + if (classtype == Class_Cone || classtype == Class_Torus) + { + // Check angle. An almost plane cone is not appropriate for + // parametrization + shared_ptr<ParamSurface> sf = surf; + shared_ptr<BoundedSurface> bdsf = + dynamic_pointer_cast<BoundedSurface,ParamSurface>(sf); + if (bdsf.get()) + sf = bdsf->underlyingSurface(); + if (classtype == Class_Cone) + { + shared_ptr<Cone> cone = + dynamic_pointer_cast<Cone,ParamSurface>(sf); + double angle = cone->getConeAngle(); + if (angle > 0.3*M_PI) + return false; + } + else if (classtype == Class_Torus) + { + shared_ptr<Torus> torus = + dynamic_pointer_cast<Torus,ParamSurface>(sf); + double rad1 = torus->getMajorRadius(); + double rad2 = torus->getMinorRadius(); + if (rad2 > 0.9*rad1) + return false; + } + } + + bool OK = RevEngUtils::parameterizeOnPrimary(points, surf, data, param, + inner1, inner2, close1, close2); + return OK; +} + + +//=========================================================================== +void RevEngRegion::analyseCylinderProperties(Point avvec, double angtol, + vector<RevEngPoint*>& in, + vector<RevEngPoint*> out) +//=========================================================================== +{ + vector<double> midang(group_points_.size()); + for (size_t ki=0; ki<group_points_.size(); ++ki) + { + Point curr = group_points_[ki]->minCurvatureVec(); + double ang = curr.angle(avvec); + ang = std::min(ang, M_PI-ang); + midang[ki] = ang; + if (ang <= angtol) + in.push_back(group_points_[ki]); + else + out.push_back(group_points_[ki]); + } + + std::sort(midang.begin(), midang.end()); + int stop_break = 1; +} + + +//=========================================================================== +bool RevEngRegion::sortByAxis(vector<Point>& axis, double tol, + double axisang, double planeang, + vector<vector<RevEngPoint*> >& groups1, + vector<vector<RevEngPoint*> >& groups2, + vector<RevEngPoint*>& remaining) +//=========================================================================== +{ + double pihalf = 0.5*M_PI; + groups1.resize(2*axis.size()); + groups2.resize(axis.size()); + for (size_t kr=0; kr<group_points_.size(); ++kr) + { + Point normal = group_points_[kr]->getLocFuncNormal(); + Point normal2 = group_points_[kr]->getTriangNormal(); + int min_ix1 = -1, min_ix2 = -1; + double min_ang1 = pihalf, min_ang2 = pihalf; + for (int ka=0; ka<(int)axis.size(); ++ka) + { + double ang = axis[ka].angle(normal); + double ang2 = axis[ka].angle(normal2); + ang = std::min(fabs(pihalf-ang), fabs(pihalf-ang2)); + if (ang < min_ang2) + { + min_ang2 = ang; + min_ix2 = ka; + } + } + for (int ka=0; ka<(int)axis.size(); ++ka) + { + double ang = axis[ka].angle(normal); + double ang2 = axis[ka].angle(normal2); + if (std::min(ang,ang2) < min_ang1) + { + min_ang1 = std::min(ang,ang2); + min_ix1 = 2*ka+1; + } + else if (std::min(M_PI-ang,M_PI-ang2) < min_ang1) + { + min_ang1 = std::min(M_PI-ang,M_PI-ang2); + min_ix1 = 2*ka; + } + } + if (min_ang1 > planeang && min_ang2 < min_ang1 && + min_ang2 < axisang && min_ix2 >= 0 ) + groups2[min_ix2].push_back(group_points_[kr]); + else if (min_ang1 < axisang && min_ix1 >= 0) + groups1[min_ix1].push_back(group_points_[kr]); + else + remaining.push_back(group_points_[kr]); + } + +#ifdef DEBUG_SEGMENT + std::ofstream of1("axis_groups1.g2"); + for (size_t ki=0; ki<groups1.size(); ++ki) + { + if (groups1[ki].size() > 0) + { + of1 << "400 1 0 4 255 0 0 255" << std::endl; + of1 << groups1[ki].size() << std::endl; + for (int ka=0; ka<(int)groups1[ki].size(); ++ka) + of1 << groups1[ki][ka]->getPoint() << std::endl; + } + } + std::ofstream of2("axis_groups2.g2"); + for (size_t ki=0; ki<groups2.size(); ++ki) + { + if (groups2[ki].size() > 0) + { + of2 << "400 1 0 4 255 0 0 255" << std::endl; + of2 << groups2[ki].size() << std::endl; + for (int ka=0; ka<(int)groups2[ki].size(); ++ka) + of2 << groups2[ki][ka]->getPoint() << std::endl; + } + } + std::ofstream of3("remaining.g2"); + if (remaining.size() > 0) + { + of3 << "400 1 0 4 0 255 0 255" << std::endl; + of3 << remaining.size() << std::endl; + for (int ka=0; ka<(int)remaining.size(); ++ka) + of3 << remaining[ka]->getPoint() << std::endl; + } +#endif + int num_groups = 0; + for (size_t ki=0; ki<groups1.size(); ++ki) + if (groups1.size() > 0) + num_groups++; + for (size_t ki=0; ki<groups2.size(); ++ki) + if (groups2.size() > 0) + num_groups++; + if (remaining.size() > 0) + num_groups++; + + return (num_groups > 1); +} + +//=========================================================================== +void RevEngRegion::removeLowAccuracyPoints(int min_pt_reg, double tol, double angtol, + vector<vector<RevEngPoint*> >& added_groups) +//=========================================================================== +{ + shared_ptr<ParamSurface> surf= getSurface(0)->surface(); + int code; + ClassType classtype = getSurface(0)->instanceType(code); + bool cyllike = (classtype == Class_Cylinder || classtype == Class_Cone); + double angtol2 = (surfflag_ == PROBABLE_HELIX) ? 0.5*M_PI : 0.25*M_PI; + + vector<vector<RevEngPoint*> > out_groups; + vector<RevEngPoint*> remain; + vector<pair<double,double> > distang; + getDistAndAng(distang); + identifyOutPoints(distang, tol, angtol, angtol2, out_groups, + remain); +#ifdef DEBUG_AXIS + std::ofstream of1("dist_separated.g2"); + of1 << "400 1 0 4 255 0 0 255" << std::endl; + of1 << remain.size() << std::endl; + for (size_t kr=0; kr<remain.size(); ++kr) + of1 << remain[kr]->getPoint() << std::endl; + for (size_t kj=0; kj<out_groups.size(); ++kj) + { + of1 << "400 1 0 4 0 255 0 255" << std::endl; + of1 << out_groups[kj].size() << std::endl; + for (size_t kr=0; kr<out_groups[kj].size(); ++kr) + of1 << out_groups[kj][kr]->getPoint() << std::endl; + } +#endif + + double maxdist, avdist; + int num_in, num2_in; + //int surf_flag2 = NOT_SET; + if (remain.size() < group_points_.size()) + { + maxdist = avdist = 0.0; + num_in = num2_in = 0; + double frac = 1.0/(double)remain.size(); + for (size_t kj=0; kj<remain.size(); ++kj) + { + double dist, ang; + remain[kj]->getSurfaceDist(dist, ang); + maxdist = std::max(maxdist, dist); + avdist += frac*dist; + if (dist <= tol) + { + num2_in++; + if (ang <= angtol) + num_in++; + } + } + int surf_flag = defineSfFlag((int)remain.size(), 0, tol, + num_in, num2_in, avdist, cyllike); + if (surf_flag <= surfflag_ && avdist < avdist_) + { + // Extract points + std::swap(group_points_, remain); + added_groups.insert(added_groups.end(), out_groups.begin(), + out_groups.end()); + + updateInfo(tol, angtol); + setSurfaceFlag(surf_flag); + updateRegionAdjacency(); + + int stop_break = 1; + } + + } + +} + +//=========================================================================== +void RevEngRegion::setPlaneParam(int min_pt_reg, Point mainaxis[3], + double tol, double angtol) +//=========================================================================== +{ + if (!hasSurface()) + return; + shared_ptr<ParamSurface> surf_init = getSurface(0)->surface(); + if (surf_init->instanceType() != Class_Plane) + return; + + shared_ptr<Plane> plane = dynamic_pointer_cast<Plane, ParamSurface>(surf_init); + int ix = -1; + double min_ang = M_PI; + double pihalf = 0.5*M_PI; + Point dir = plane->direction(); + for (int ka=0; ka<3; ++ka) + { + double ang = mainaxis[ka].angle(dir); + ang = fabs(pihalf-ang); + if (ang < min_ang) + { + min_ang = ang; + ix = ka; + } + } + + Point dir2 = dir.cross(mainaxis[ix]); + dir2.normalize(); + std::vector<double> rot_mat = GeometryTools::getRotationMatrix(dir2, min_ang); + Point rotated(3); + for (int ka=0; ka<3; ++ka) + for (int kb=0; kb<3; ++kb) + rotated[ka] += rot_mat[ka*3+kb]*dir[kb]; + + bool updated = updateSurfaceWithAxis(min_pt_reg, rotated, mainaxis, -1, tol, + angtol, plane->location()); + + shared_ptr<Plane> plane2(new Plane(plane->location(), plane->direction(), mainaxis[ix])); + + // Reparameterize. The accuracy should stay the same + double maxd, avd; + int num_in, num2_in; + vector<pair<double, double> > dist_ang; + vector<double> parvals; + vector<RevEngPoint*> inpt, outpt; + RevEngUtils::distToSurf(group_points_.begin(), group_points_.end(), + plane, tol, maxd, avd, num_in, num2_in, inpt, outpt, + parvals, dist_ang, angtol); + + int sf_flag = defineSfFlag(0, tol, num_in, num2_in, avd, false); + for (size_t kh=0; kh<group_points_.size(); ++kh) + { + group_points_[kh]->setPar(Vector2D(parvals[2*kh], parvals[2*kh+1])); + group_points_[kh]->setSurfaceDist(dist_ang[kh].first, dist_ang[kh].second); + } + HedgeSurface *hedge = getSurface(0); + hedge->replaceSurf(plane2); + setSurfaceFlag(sf_flag); + updateInfo(tol, angtol); + surf_adaption_ = AXIS_ADAPTED; + +} + +//=========================================================================== +bool RevEngRegion::updateSurfaceWithAxis(int min_pt_reg, Point adj_axis, + Point mainaxis[3], int ix, double tol, + double angtol, Point pos) +//=========================================================================== +{ + bool updated = false; + if (!hasSurface()) + return false; + vector<Point> curr_axis; + if (adj_axis.dimension() != 0) + curr_axis.push_back(adj_axis); + if (ix >=0 && ix < 3) + curr_axis.push_back(mainaxis[ix]); + if (curr_axis.size() == 0) + return false; + + shared_ptr<ParamSurface> surf_init = getSurface(0)->surface(); + int code; + ClassType classtype = getSurface(0)->instanceType(code); + bool cyllike = (classtype == Class_Cylinder || classtype == Class_Cone); + //double angtol2 = (surfflag_ == PROBABLE_HELIX) ? 0.5*M_PI : 0.25*M_PI; + + // Ensure updated information + double maxdist1 = 0.0, avdist1 = 0.0; + int num_in1 = 0, num2_in1 = 0; + double frac = 1.0/(double)group_points_.size(); + for (size_t kj=0; kj<group_points_.size(); ++kj) + { + double dist, ang; + group_points_[kj]->getSurfaceDist(dist, ang); + maxdist1 = std::max(maxdist1, dist); + avdist1 += frac*dist; + if (dist <= tol) + { + num2_in1++; + if (ang <= angtol) + num_in1++; + } + } + int sf_flag1 = defineSfFlag(0, tol, num_in1, num2_in1, + avdist1, cyllike); + + vector<double> maxdist(curr_axis.size()); + vector<double> avdist(curr_axis.size()); + vector<int> num_in(curr_axis.size()); + vector<int> num2_in(curr_axis.size()); + vector<vector<pair<double, double> > > dist_ang(curr_axis.size()); + vector<vector<double> > parvals(curr_axis.size()); + vector<int> sf_flag(curr_axis.size()); + vector<shared_ptr<ParamSurface> > surf(curr_axis.size()); + for (size_t ki=0; ki<curr_axis.size(); ++ki) + { + // Update surface + surf[ki] = surfaceWithAxis(group_points_, curr_axis[ki], pos, + mainaxis); + + // Check accuracy + vector<RevEngPoint*> inpt, outpt; + RevEngUtils::distToSurf(group_points_.begin(), group_points_.end(), + surf[ki], tol, maxdist[ki], avdist[ki], num_in[ki], + num2_in[ki], inpt, outpt, parvals[ki], + dist_ang[ki], angtol); + + sf_flag[ki] = defineSfFlag(0, tol, num_in[ki], num2_in[ki], + avdist[ki], cyllike); + + } + + // Prefer axis adapted + int numpt = numPoints(); + double avfrac = 0.9; + double fracfrac = 0.9; + double tol2 = 0.5*tol; + int alt_ix = (curr_axis.size() > 1) ? 1 : 0; + if (alt_ix > 0) + { + double num_frac1 = (double)(num_in[0]+num2_in[0])/(double)numpt; + double num_frac2 = (double)(num_in[1]+num2_in[1])/(double)numpt; + if ((avdist[0] <= avfrac*avdist[1] || avdist[0] <= tol2) && + fracfrac*num_frac1 >= num_frac2) + alt_ix = 0; + } + + //double num_frac = (double)(num_in1+num2_in1)/(double)numpt; + //double num_frac_alt = (double)(num_in[alt_ix]+num2_in[alt_ix])/(double)numpt; + // if ((avfrac*avdist[alt_ix] <= avdist1 || avdist[alt_ix] <= tol2) && + // num_frac_alt >= fracfrac*num_frac) + if (sf_flag[alt_ix] < ACCURACY_POOR || sf_flag[alt_ix] <= sf_flag1) + { + // Replace + setBaseSf(surf_init, maxdist1, avdist1, num_in1, num2_in1); + for (size_t kh=0; kh<group_points_.size(); ++kh) + { + group_points_[kh]->setPar(Vector2D(parvals[alt_ix][2*kh], + parvals[alt_ix][2*kh+1])); + group_points_[kh]->setSurfaceDist(dist_ang[alt_ix][kh].first, + dist_ang[alt_ix][kh].second); + } + HedgeSurface *hedge = getSurface(0); + hedge->replaceSurf(surf[alt_ix]); + if (!surf[alt_ix]->isBounded()) + { + double diag = bbox_.low().dist(bbox_.high()); + hedge->limitSurf(2*diag); + } + setSurfaceFlag(sf_flag[alt_ix]); + updateInfo(tol, angtol); + for (size_t kj=0; kj<rev_edges_.size(); ++kj) + { + rev_edges_[kj]->replaceSurf(this, surf[alt_ix], tol); + rev_edges_[kj]->increaseSurfChangeCount(); + } + surf_adaption_ = (adj_axis.dimension() != 0 && alt_ix == 0) ? + ADJACENT_ADAPTED : AXIS_ADAPTED; + updated = true; + } + else + { + // Store alternative as base surface + setBaseSf(surf[alt_ix], maxdist[alt_ix], avdist[alt_ix], + num_in[alt_ix], num2_in[alt_ix]); + + setAccuracy(maxdist1, avdist1, num_in1, num2_in1); + } + + int stop_break = 1; + + return updated; +} + +//=========================================================================== +void RevEngRegion::updateSurfaceAndInfo(shared_ptr<ParamSurface> surf, + double tol, double angtol, + vector<double>& parvals, + vector<pair<double,double> >& dist_ang, + vector<RevEngEdge*>& nopar_edgs) +//=========================================================================== +{ + if (parvals.size() != 2*group_points_.size() || + dist_ang.size() != group_points_.size()) + THROW("RevEngRegion::updateSurfaceAndInfo: Inconsistent input"); + + shared_ptr<ParamSurface> surf_init = getSurface(0)->surface(); + + // Replace + setBaseSf(surf_init, maxdist_, avdist_, num_inside_, num_inside2_); + for (size_t kh=0; kh<group_points_.size(); ++kh) + { + group_points_[kh]->setPar(Vector2D(parvals[2*kh], + parvals[2*kh+1])); + group_points_[kh]->setSurfaceDist(dist_ang[kh].first, + dist_ang[kh].second); + } + HedgeSurface *hedge = getSurface(0); + hedge->replaceSurf(surf); + if (!surf->isBounded()) + { + double diag = bbox_.low().dist(bbox_.high()); + hedge->limitSurf(2*diag); + } + updateInfo(tol, angtol); + bool cyl_like = ((surf->instanceType() == Class_Cylinder || + surf->instanceType() == Class_Cone)); + + int sf_flag = defineSfFlag((int)group_points_.size(), 0, tol, num_inside_, + num_inside2_, avdist_, cyl_like); + setSurfaceFlag(sf_flag); + for (size_t kj=0; kj<rev_edges_.size(); ++kj) + { + rev_edges_[kj]->replaceSurf(this, surf, tol); + rev_edges_[kj]->increaseSurfChangeCount(); + int missing = rev_edges_[kj]->missingParCrv(); + if (missing > 0) + nopar_edgs.push_back(rev_edges_[kj]); + } +} + +//=========================================================================== +void RevEngRegion::rangeAlongAxis(const Point& pos, const Point& axis, + double& tmin, double& tmax) +//=========================================================================== +{ + tmin = std::numeric_limits<double>::max(); + tmax = std::numeric_limits<double>::lowest(); + for (size_t ki=0; ki<group_points_.size(); ++ki) + { + Vector3D xyz = group_points_[ki]->getPoint(); + Point point(xyz[0], xyz[1], xyz[2]); + double tpar = (point - pos)*axis; + tmin = std::min(tmin, tpar); + tmax = std::max(tmax, tpar); + } +} + +//=========================================================================== +void RevEngRegion::identifyOutPoints(vector<pair<double,double> >& distang, + double tol, double angtol, double angtol2, + vector<vector<RevEngPoint*> >& out_groups, + vector<RevEngPoint*>& remaining) +//=========================================================================== +{ + // Identify points with poor accuracy + double fac = 2.0; + vector<RevEngPoint*> points_poor; + for (size_t ki=0; ki<group_points_.size(); ++ki) + if ((distang[ki].second > angtol && distang[ki].first > tol) || + distang[ki].first > fac*tol || distang[ki].second > angtol2) + points_poor.push_back(group_points_[ki]); + else + remaining.push_back(group_points_[ki]); + + // Release points in the inner of the group + if (points_poor.size() > 0) + { + vector<RevEngPoint*> inner; + connectedGroups(points_poor, out_groups, true, inner); + if (inner.size() > 0) + remaining.insert(remaining.end(), inner.begin(), inner.end()); + } +} + +//=========================================================================== +shared_ptr<ParamSurface> RevEngRegion::surfaceWithAxis(vector<RevEngPoint*>& points, + Point axis, Point pos, + Point mainaxis[3]) +//=========================================================================== +{ + shared_ptr<ParamSurface> surf; + if (!hasSurface()) + return surf; + + shared_ptr<ParamSurface> init_surf = getSurface(0)->surface(); + shared_ptr<ElementarySurface> elem = + dynamic_pointer_cast<ElementarySurface,ParamSurface>(init_surf); + if (!elem.get()) + return surf; + + Point low = bbox_.low(); + Point high = bbox_.high(); + Point loc = elem->location(); + if (hasBlendEdge()) + { + // Maintain radius while updating surface + surf = init_surf; // For the time being + } + else if (elem->instanceType() == Class_Plane) + { + Point init_norm = elem->direction(); + surf = RevEngUtils::planeWithAxis(points, axis, loc, mainaxis); + if (axis*init_norm < 0.0) + surf->swapParameterDirection(); + } + else if (elem->instanceType() == Class_Cylinder) + surf = RevEngUtils::cylinderWithAxis(points, axis, low, high, + mainaxis); + else if (elem->instanceType() == Class_Torus) + surf = RevEngUtils::torusWithAxis(points, axis, + pos.dimension() == 0 ? loc : pos, + mainaxis); + else if (elem->instanceType() == Class_Sphere) + surf = RevEngUtils::sphereWithAxis(points, axis, mainaxis); + else if (elem->instanceType() == Class_Cone) + surf = RevEngUtils::coneWithAxis(points, axis, low, high, + mainaxis); + + return surf; +} + + +//=========================================================================== +void RevEngRegion::axisFromAdjacent(double angtol, vector<Point>& axis) +//=========================================================================== +{ + vector<pair<shared_ptr<ElementarySurface>, RevEngRegion*> > adj_elem, adj_elem_base; + getAdjacentElemInfo(adj_elem, adj_elem_base); + + for (size_t ki=0; ki<adj_elem.size(); ++ki) + { + if (adj_elem[ki].first->instanceType() == Class_Plane || + adj_elem[ki].first->instanceType() == Class_Cylinder || + adj_elem[ki].first->instanceType() == Class_Torus) + { + Point dir = adj_elem[ki].first->direction(); + size_t kj; + for (kj=0; kj<axis.size(); ++kj) + { + double ang = dir.angle(axis[kj]); + ang = std::min(ang, M_PI-ang); + if (ang < angtol) + break; + } + if (kj == axis.size()) + axis.push_back(dir); + } + } +} + +//=========================================================================== +bool RevEngRegion::divideWithSegInfo(int seg_ix, int min_pt_reg, + vector<vector<RevEngPoint*> >& sep_groups, + vector<RevEngPoint*>& single_pts) +//=========================================================================== +{ + if (seg_ix < 0 || seg_ix >= (int)seg_info_.size()) + return false; + + if (seg_info_[seg_ix]->type_ != 1) + return false; // No strategy + + // Extract points outside a belt around the specified axis + Point axis = seg_info_[seg_ix]->axis_; + Point pos = seg_info_[seg_ix]->loc_; + double lim1 = seg_info_[seg_ix]->min_dist_; + double lim2 = seg_info_[seg_ix]->max_dist_; + vector<RevEngPoint*> inside, outside; + for (size_t kr=0; kr<group_points_.size(); ++kr) + { + Vector3D xyz = group_points_[kr]->getPoint(); + Point xyz2(xyz[0], xyz[1], xyz[2]); + Point onaxis = pos + ((xyz2-pos)*axis)*axis; + double dd = xyz2.dist(onaxis); + if (dd >= lim1 && dd <= lim2) + inside.push_back(group_points_[kr]); + else + outside.push_back(group_points_[kr]); + } + + // Check for a reasonably balanced segmentation + int min_num = std::min(min_pt_reg, (int)group_points_.size()/10); + if ((int)inside.size() < min_num || (int)outside.size() < min_num) + return false; + + // Ensure connected point groups + vector<std::vector<RevEngPoint*> > sep1, sep2; + std::vector<RevEngPoint*> dummy; + connectedGroups(inside, sep1, false, dummy); + connectedGroups(outside, sep2, false, dummy); + sep1.insert(sep1.end(), sep2.begin(), sep2.end()); + + // Identify largest group + int max_num = 0; + int ix = -1; + for (size_t ki=0; ki<sep1.size(); ++ki) + if ((int)sep1[ki].size() > max_num) + { + max_num = (int)sep1[ki].size(); + ix = (int)ki; + } + + if (ix >= 0) + { + group_points_.clear(); + group_points_ = sep1[ix]; + + // Update bounding box and principal curvature summary + updateInfo(); + + for (size_t kj=0; kj<sep1.size(); ++kj) + { + if ((int)kj == ix) + continue; + if (sep1[kj].size() == 1) + { + sep1[kj][0]->unsetRegion(); + single_pts.push_back(sep1[kj][0]); + } + else + sep_groups.push_back(sep1[kj]); + } + } + return true; +} + + +//=========================================================================== +bool RevEngRegion::extractCylByAxis(Point mainaxis[3], int min_point, + int min_pt_reg, double tol, + double angtol, int prefer_elementary, + vector<shared_ptr<HedgeSurface> >& hedgesfs, + vector<shared_ptr<RevEngRegion> >& added_reg, + vector<vector<RevEngPoint*> >& out_groups, + vector<RevEngPoint*>& single_pts) +//=========================================================================== +{ + // Get axis from adjacent + vector<Point> axis; + axisFromAdjacent(angtol, axis); + + double pihalf = 0.5*M_PI; + double axisang = 0.1*M_PI; + vector<vector<RevEngPoint*> > axis_groups(3); + vector<RevEngPoint*> remaining; + for (size_t kr=0; kr<group_points_.size(); ++kr) + { + Point normal = group_points_[kr]->getLocFuncNormal(); + int min_ix = -1; + double min_ang = pihalf; + for (int ka=0; ka<3; ++ka) + { + double ang = mainaxis[ka].angle(normal); + ang = fabs(pihalf-ang); + if (ang < min_ang) + { + min_ang = ang; + min_ix = ka; + } + } + if (min_ang < axisang && min_ix >= 0) + axis_groups[min_ix].push_back(group_points_[kr]); + else + remaining.push_back(group_points_[kr]); + } + +#ifdef DEBUG_SEGMENT + std::ofstream of("axis_groups.g2"); + for (size_t ki=0; ki<axis_groups.size(); ++ki) + { + if (axis_groups[ki].size() > 0) + { + of << "400 1 0 4 255 0 0 255" << std::endl; + of << axis_groups[ki].size() << std::endl; + for (int ka=0; ka<(int)axis_groups[ki].size(); ++ka) + of << axis_groups[ki][ka]->getPoint() << std::endl; + } + } + if (remaining.size() > 0) + { + of << "400 1 0 4 0 255 0 255" << std::endl; + of << remaining.size() << std::endl; + for (int ka=0; ka<(int)remaining.size(); ++ka) + of << remaining[ka]->getPoint() << std::endl; + } +#endif + + size_t remain_size = remaining.size(); + for (int ka=0; ka<(int)axis_groups.size(); ++ka) + if (axis_groups[ka].size() < remain_size) + { + remaining.insert(remaining.end(), axis_groups[ka].begin(), axis_groups[ka].end()); + axis_groups[ka].clear(); + } + + double remain_fac = 0.9; + if ((double)remaining.size()/(double)group_points_.size() > remain_fac) + return false; // Not a feasible segmentation + for (int ka=0; ka<3; ++ka) + if (axis_groups[ka].size() == group_points_.size()) + return false; + + // Split into connected groups + for (size_t ki=0; ki<axis_groups.size(); ++ki) + { + if ((int)axis_groups[ki].size() < min_point) + { + if (axis_groups[ki].size() > 0) + remaining.insert(remaining.end(), axis_groups[ki].begin(), + axis_groups[ki].end()); + continue; + } + + vector<vector<RevEngPoint*> > grouped; + std::vector<RevEngPoint*> dummy; + connectedGroups(axis_groups[ki], grouped, false, dummy); + + for (size_t kj=0; kj<grouped.size(); ++kj) + { + if ((int)grouped[kj].size() < min_point) + { + remaining.insert(remaining.end(), grouped[kj].begin(), + grouped[kj].end()); + continue; + } + + // Try to fit a cylinder + shared_ptr<RevEngRegion> tmp_reg(new RevEngRegion(classification_type_, + edge_class_type_, + grouped[kj])); + tmp_reg->setRegionAdjacency(); + vector<HedgeSurface*> prevsfs; + bool repeat = false; + bool found = tmp_reg->extractCylinder(tol, min_point, min_pt_reg, + angtol, + prefer_elementary, hedgesfs, + prevsfs, out_groups, repeat); + added_reg.push_back(tmp_reg); + } + } + + vector<vector<RevEngPoint*> > grouped2; + std::vector<RevEngPoint*> dummy; + connectedGroups(remaining, grouped2, false, dummy); + + int max_num = 0; + int max_ix = -1; + for (size_t ki=0; ki<grouped2.size(); ++ki) + if ((int)grouped2[ki].size() > max_num) + { + max_num = (int)grouped2[ki].size(); + max_ix = (int)ki; + } + + if (max_ix >= 0) + { + std::swap(group_points_, grouped2[max_ix]); + std::swap(grouped2[max_ix], grouped2[grouped2.size()-1]); + grouped2.pop_back(); + updateInfo(tol, angtol); + } + if (grouped2.size() > 0) + out_groups.insert(out_groups.end(), grouped2.begin(), grouped2.end()); + + return true; +} + +//=========================================================================== +void RevEngRegion::computeFracNorm(double angtol, Point mainaxis[3], + int nmb_axis[3], double& in_frac1, + double& in_frac2) +//=========================================================================== +{ + double pihalf = 0.5*M_PI; + double axisang = 0.1*M_PI; + nmb_axis[0] = nmb_axis[1] = nmb_axis[2] = 0; + if (normalcone_.angle() <= angtol) + in_frac1 = 1.0; + else + { + int nmb_in = 0; + for (size_t kr=0; kr<group_points_.size(); ++kr) + { + Point normal = group_points_[kr]->getLocFuncNormal(); + if (avnorm_.angle(normal) <= angtol) + nmb_in++; + for (int ka=0; ka<3; ++ka) + { + double ang = mainaxis[ka].angle(normal); + if (fabs(pihalf-ang) < axisang) + nmb_axis[ka]++; + } + + } + in_frac1 = (double)nmb_in/(double)group_points_.size(); + } + frac_norm_in_ = in_frac1; + + if (normalcone2_.angle() <= angtol) + in_frac2 = 1.0; + else + { + int nmb_in = 0; + for (size_t kr=0; kr<group_points_.size(); ++kr) + { + Point normal = group_points_[kr]->getTriangNormal(); + if (avnorm2_.angle(normal) <= angtol) + nmb_in++; + for (int ka=0; ka<3; ++ka) + { + double ang = mainaxis[ka].angle(normal); + if (fabs(pihalf-ang) < axisang) + nmb_axis[ka]++; + } + + } + in_frac2 = (double)nmb_in/(double)group_points_.size(); + } + frac_norm_in2_ = in_frac2; +} + +//=========================================================================== +void +RevEngRegion::initPlaneCyl(int min_point, int min_pt_reg, double tol, + double angtol, Point mainaxis[3], + double zero_H, double zero_K, + vector<shared_ptr<HedgeSurface> >& hedgesfs, + vector<vector<RevEngPoint*> >& out_groups, + vector<RevEngPoint*>& single_pts, bool& repeat) +//=========================================================================== +{ +#ifdef DEBUG_SEGMENT + std::ofstream of1("init_sf_region.g2"); + writeRegionPoints(of1); +#endif + + repeat = false; + + // Count fraction of normals closer to the centre than the tolerance + double angtol2 = 2.0*angtol; + //double dfrac = 0.75; + double in_frac, in_frac2; + int nmb_axis[3]; + computeFracNorm(angtol2, mainaxis, nmb_axis, in_frac, in_frac2); + + int min_pt_reg2 = 4*min_pt_reg/5; // Allow some slack + + // Initial approximation with plane and cylinder + vector<shared_ptr<ElementarySurface> > elemsf(6); + vector<double> maxd(6), avd(6); + vector<int> num_in(6), num2_in(6); + vector<vector<double> > param(6); + vector<vector<pair<double,double> > > d_a(6); + vector<int> surfflag(6, NOT_SET); + + double in_lim = 0.9; + shared_ptr<Plane> plane = computePlane(group_points_, avnorm_, mainaxis); + vector<RevEngPoint*> inpt1, outpt1, inpt2, outpt2; + int num_ang_in1=0, num_ang_in2=0; + RevEngUtils::distToSurf(group_points_.begin(), group_points_.end(), plane, + tol, maxd[4], avd[4], num_in[4], num2_in[4], + inpt1, outpt1, param[4], d_a[4], angtol); + for (size_t kr=0; kr<d_a[4].size(); ++kr) + { + if (d_a[4][kr].second < angtol) + num_ang_in1++; + } + elemsf[4] = plane; + surfflag[4] = defineSfFlag(0, tol, num_in[4], num2_in[4], avd[4], + false); + + shared_ptr<Cylinder> cyl = computeCylinder(group_points_, tol); + RevEngUtils::distToSurf(group_points_.begin(), group_points_.end(), cyl, + tol, maxd[5], avd[5], num_in[5], num2_in[5], + inpt2, outpt2, param[5], d_a[5], angtol); + + for (size_t kr=0; kr<d_a[5].size(); ++kr) + { + if (d_a[5][kr].second < angtol) + num_ang_in2++; + } + elemsf[5] = cyl; + surfflag[5] = defineSfFlag(0, tol, num_in[5], num2_in[5], avd[5], + true); + + // Check with reduced point set + vector<vector<RevEngPoint*> > remaining(4); + vector<vector<vector<RevEngPoint*> > > extracted(6); // Two last is empty + + int min_ang_in = (int)group_points_.size()/20; + int min_ang_in2 = (int)group_points_.size()/5; + double dfac = 3.0; + int nfac = 2; + if (accuracyOK(min_point, tol, num_in[4], avd[4]) == false && + avd[4] < avd[5] && avd[4] < dfac*tol && num2_in[4] > num2_in[5] && + num_ang_in1 > min_ang_in && num_ang_in1 > min_point) + { + // Search for a (reasonable) connected planar component in the point cloud + Point vec = plane->direction(); + elemsf[0] = planarComponent(vec, min_point, min_pt_reg2, + tol, angtol, mainaxis, + remaining[0], extracted[0]); + } + + if (accuracyOK(min_point, tol, num_in[5], avd[5]) == false && + normalcone_.greaterThanPi() && avd[5] < avd[4] && avd[5] < dfac*tol && + num2_in[5] >= nfac*num_in[5]) + { + // Potential helical surface. Cleanup in points and register occurance + elemsf[1] = helicalComponent(cyl, tol, angtol, min_point, min_pt_reg2, + avd[5], num2_in[5], d_a[5], + remaining[1], extracted[1], + maxd[1], avd[1], num_in[1], num2_in[1], + param[1], d_a[1]); + } + + vector<vector<RevEngPoint*> > out_gr2; + if ((in_frac >= in_lim && (!(MAH_ > 10.0*MAK_ && MAH_ > 0.1))) || + accuracyOK(min_point, tol, num_in[4], avd[4]) || + num_ang_in1 >= min_ang_in2) + { + vector<RevEngPoint*> remain1; + vector<vector<RevEngPoint*> > out_gr1; + identifyOutPoints(d_a[4], tol, angtol, angtol2, out_gr1, remain1); + +#ifdef DEBUG_SEGMENT + if (out_gr1.size() > 0) + { + std::ofstream ofa("ang_points1.g2"); + ofa << "400 1 0 4 255 0 0 255" << std::endl; + ofa << remain1.size() << std::endl; + for (size_t kr=0; kr<remain1.size(); ++kr) + ofa << remain1[kr]->getPoint() << std::endl; + for (size_t kh=0; kh<out_gr1.size(); ++kh) + { + ofa << "400 1 0 4 50 50 155 255" << std::endl; + ofa << out_gr1[kh].size() << std::endl; + for (size_t kr=0; kr<out_gr1[kh].size(); ++kr) + ofa << out_gr1[kh][kr]->getPoint() << std::endl; + } + } +#endif + + if ((int)remain1.size() > min_pt_reg2) + { + vector<vector<RevEngPoint*> > connected; + vector<RevEngPoint*> inner; + connectedGroups(remain1, connected, false, inner); + for (size_t kr=1; kr<connected.size(); ++kr) + if (connected[kr].size() > connected[0].size()) + std::swap(connected[0], connected[kr]); + std::swap(remain1, connected[0]); + out_gr1.insert(out_gr1.end(), connected.begin()+1, connected.end()); + + elemsf[2] = computePlane(remain1, avnorm_, mainaxis); + remaining[2] = remain1; + extracted[2] = out_gr1; + } + } + + if (MAH_ > 3*MAK_ || accuracyOK(min_point, tol, num_in[5], avd[5]) || + num_ang_in2 >= min_ang_in2) + { + vector<RevEngPoint*> remain2; + identifyOutPoints(d_a[5], tol, angtol, angtol2, out_gr2, remain2); + +#ifdef DEBUG_SEGMENT + if (out_gr2.size() > 0) + { + std::ofstream ofa("ang_points2.g2"); + ofa << "400 1 0 4 255 0 0 255" << std::endl; + ofa << remain2.size() << std::endl; + for (size_t kr=0; kr<remain2.size(); ++kr) + ofa << remain2[kr]->getPoint() << std::endl; + for (size_t kh=0; kh<out_gr2.size(); ++kh) + { + ofa << "400 1 0 4 50 50 155 255" << std::endl; + ofa << out_gr2[kh].size() << std::endl; + for (size_t kr=0; kr<out_gr2[kh].size(); ++kr) + ofa << out_gr2[kh][kr]->getPoint() << std::endl; + } + } +#endif + + double rfac = 0.5; + //size_t remain2_size = remain2.size(); + if ((double)remain2.size() < rfac*(double)group_points_.size()) + { + vector<RevEngPoint*> ang_pts; + vector<RevEngPoint*> remain_ang; + double dtol = 2.0*avd[5]; + identifyAngPoints(d_a[5], angtol, tol, dtol, ang_pts, remain_ang); + +#ifdef DEBUG_SEGMENT + std::ofstream ofa("ang_pts_cyl.g2"); + ofa << "400 1 0 4 155 50 50 255" << std::endl; + ofa << ang_pts.size() << std::endl; + for (size_t kr=0; kr<ang_pts.size(); ++kr) + ofa << ang_pts[kr]->getPoint() << std::endl; +#endif + if (remain_ang.size() > remain2.size()) + { + std::swap(remain_ang, remain2); + vector<vector<RevEngPoint*> > connected2; + vector<RevEngPoint*> dummy_inner; + connectedGroups(ang_pts, connected2, false, dummy_inner); + std::swap(out_gr2, connected2); + } + } + + if ((int)remain2.size() > min_pt_reg2) + { + shared_ptr<Cylinder> cyl2 = computeCylinder(remain2, tol); + + double len = bbox_.low().dist(bbox_.high()); + Point axis = cyl2->direction(); + Point Cx = cyl2->direction2(); + Point loc = cyl2->location(); + shared_ptr<Cone> cone = + RevEngUtils::coneWithAxis(remain2, axis, Cx, loc, len); + + // Check accuracy with respect to reduced point cloud + // For cylinder + double maxdist3, avdist3; + int num_inside3, num2_inside3=0; + vector<RevEngPoint*> inpt3, outpt3; + vector<double> parvals3; + vector<pair<double, double> > dist_ang3; + RevEngUtils::distToSurf(remain2.begin(), remain2.end(), cyl2, + tol, maxdist3, avdist3, num_inside3, + num2_inside3, inpt3, outpt3, parvals3, + dist_ang3, angtol); + int sf_flag3 = defineSfFlag((int)remain2.size(), 0, tol, num_inside3, + num2_inside3, avdist3, true); + + // For cone + int sf_flag4 = NOT_SET; + double maxdist4, avdist4; + int num_inside4, num2_inside4=0; + vector<RevEngPoint*> inpt4, outpt4; + vector<double> parvals4; + vector<pair<double, double> > dist_ang4; + double cone_fac = 0.1*angtol; + if (sf_flag3 >= ACCURACY_POOR || + fabs(cone->getConeAngle()) > cone_fac*angtol) + { + vector<RevEngPoint*> inpt4, outpt4; + RevEngUtils::distToSurf(remain2.begin(), remain2.end(), cone, + tol, maxdist4, avdist4, num_inside4, + num2_inside4, inpt4, outpt4, parvals4, + dist_ang4, angtol); + sf_flag4 = defineSfFlag((int)remain2.size(), 0, tol, num_inside4, + num2_inside4, avdist4, true); + } + + if (std::min(sf_flag3, sf_flag4) < ACCURACY_POOR) + { + remaining[3] = remain2; + extracted[3] = out_gr2; + + if (sf_flag3 < sf_flag4 || + (sf_flag3 == sf_flag4 && + (avdist3 < avdist4 || num_inside3 > num_inside4))) + { + elemsf[3] = cyl2; + maxd[3] = maxdist3; + avd[3] = avdist3; + num_in[3] = num_inside3; + num2_in[3] = num2_inside3; + param[3] = parvals3; + d_a[3] = dist_ang3; + surfflag[3] = sf_flag3; + } + else + { + elemsf[3] = cone; + maxd[3] = maxdist4; + avd[3] = avdist4; + num_in[3] = num_inside4; + num2_in[3] = num2_inside4; + param[3] = parvals4; + d_a[3] = dist_ang4; + surfflag[3] = sf_flag4; + } + } + } + } + + // Compute accuracy for remaining candidates + for (size_t ki=0; ki<elemsf.size(); ++ki) + { + if (!elemsf[ki].get()) + continue; // Not a candidate + if (surfflag[ki] < NOT_SET) + continue; // Already computed + + if (param[ki].size() == 0) + { + vector<RevEngPoint*> inpt3, outpt3; + RevEngUtils::distToSurf(remaining[ki].begin(), remaining[ki].end(), + elemsf[ki], tol, maxd[ki], avd[ki], + num_in[ki], num2_in[ki], inpt3, outpt3, + param[ki], d_a[ki], angtol); + } + bool cyllike = (elemsf[ki]->instanceType() == Class_Cylinder || + elemsf[ki]->instanceType() == Class_Cone); + surfflag[ki] = defineSfFlag((int)remaining[ki].size(), 0, tol, + num_in[ki], num2_in[ki], avd[ki], cyllike); + } + + // Select surface + int perm[6] = {4, 5, 2, 3, 0, 1}; + size_t num_pts_in[6]; + for (size_t kr=0; kr<4; ++kr) + num_pts_in[kr] = remaining[kr].size(); + num_pts_in[4] = num_pts_in[5] = group_points_.size(); + double size_fac = 0.9; + double avd_fac = 0.95; + + int ix = -1; + for (int ka=0; ka<6; ++ka) + { + if (surfflag[perm[ka]] >= ACCURACY_POOR) + continue; + if (ix < 0) + ix = ka; + else + { + if (surfflag[perm[ka]] == surfflag[perm[ix]] || + (surfflag[perm[ka]] == ANGULAR_DEVIATION && + surfflag[perm[ix]] == PROBABLE_HELIX) || + (surfflag[perm[ix]] == ANGULAR_DEVIATION && + surfflag[perm[ka]] == PROBABLE_HELIX)) + { + //int curr_num = std::max(num_pts_in[perm[ix]], num_pts_in[perm[ka]]); + int curr_num = ((int)num_pts_in[perm[ix]] + + (int)num_pts_in[perm[ka]])/2; + double frac1 = (double)(num_in[perm[ix]] + num2_in[perm[ix]])/ + (double)curr_num; + double frac2 = (double)(num_in[perm[ka]] + num2_in[perm[ka]])/ + (double)curr_num; + + bool prefer_first = false; + if (perm[ix] % 2 == 0 && perm[ka] % 2 == 1) + { + // Replace plane by rotational surface? + double r = elemsf[perm[ka]]->radius(0.0, 0.0); + double d = bbox_.low().dist(bbox_.high()); + double x2 = 4*r*r - d*d; + double x = (x2 > 0.0) ? r - 0.5*sqrt(x2) : r; + double rfac = 0.05; + if (x < rfac*r) + prefer_first = true; + } + + + if (prefer_first) + ; // Keep current + else if (avd[perm[ka]] <= tol && avd_fac*avd[perm[ix]] > tol) + ix = ka; + else if (size_fac*(double)num_pts_in[perm[ka]] > + (double)num_pts_in[perm[ix]]) + ix = ka; + else if (avd[perm[ka]] < avd_fac*avd[perm[ix]] && frac2 > frac1) + ix = ka; + + } + else if (surfflag[perm[ka]] < surfflag[perm[ix]]) + ix = ka; + } + } + + if (ix >= 0) + { + // Surface found + int ix2 = perm[ix]; + + // Pre check for connected group + vector<vector<RevEngPoint*> > grouped; + std::vector<RevEngPoint*> dummy; + connectedGroups((ix2<4) ? remaining[ix2] : group_points_, grouped, + false, dummy); + int ix3 = 0; + for (size_t kr=1; kr<grouped.size(); ++kr) + if (grouped[kr].size() > grouped[ix3].size()) + ix3 = (int)kr; + + if (grouped[ix3].size() < min_pt_reg2 || (!elemsf[ix2].get())) + ix = -1; + } + + if (ix >= 0) + { + // Surface found + int ix2 = perm[ix]; + + if (ix2 < 4) + std::swap(group_points_, remaining[ix2]); + + for (size_t kh=0; kh<group_points_.size(); ++kh) + { + group_points_[kh]->setPar(Vector2D(param[ix2][2*kh], + param[ix2][2*kh+1])); + group_points_[kh]->setSurfaceDist(d_a[ix2][kh].first, + d_a[ix2][kh].second); + } + setAccuracy(maxd[ix2], avd[ix2], num_in[ix2], num2_in[ix2]); + shared_ptr<HedgeSurface> hedge(new HedgeSurface(elemsf[ix2], this)); + setHedge(hedge.get()); + hedgesfs.push_back(hedge); + setSurfaceFlag(surfflag[ix2]); + + // Ensure connected region + size_t num_extract = extracted[ix2].size(); + for (size_t kr=0; kr<extracted[ix2].size(); ++kr) + for (size_t kh=0; kh<extracted[ix2][kr].size(); ++kh) + extracted[ix2][kr][kh]->unsetRegion(); + + vector<vector<RevEngPoint*> > separate_groups; + splitRegion(separate_groups); + if (separate_groups.size() > 0) + { + extracted[ix2].insert(extracted[ix2].end(), separate_groups.begin(), + separate_groups.end()); + + for (size_t kr=num_extract; kr<extracted[ix2].size(); ++kr) + for (size_t kh=0; kh<extracted[ix2][kr].size(); ++kh) + extracted[ix2][kr][kh]->unsetRegion(); + + if (hasSurface()) + checkReplaceSurf(mainaxis, min_pt_reg, tol, angtol); + } + + for (size_t kr=0; kr<extracted[ix2].size(); ) + { + if (extracted[ix2][kr].size() == 1) + { + extracted[ix2][kr][0]->unsetRegion(); + single_pts.push_back(extracted[ix2][kr][0]); + extracted[ix2].erase(extracted[ix2].begin()+kr); + } + else + ++kr; + } + out_groups = extracted[ix2]; + +#ifdef DEBUG_SEGMENT + std::ofstream ofb("res_group.g2"); + writeRegionPoints(ofb); + writeSurface(ofb); +#endif + int stop_break = 1; + } +} + + + + +//=========================================================================== +void RevEngRegion::splitRegion(vector<vector<RevEngPoint*> >& separate_groups) +//=========================================================================== +{ + vector<vector<RevEngPoint*> > connected; + for (size_t ki=0; ki<group_points_.size(); ++ki) + { + if (group_points_[ki]->visited()) + continue; + vector<RevEngPoint*> curr_group; + group_points_[ki]->fetchConnected(this, (int)group_points_.size(), curr_group); + connected.push_back(curr_group); + } + + for (size_t ki=0; ki<group_points_.size(); ++ki) + { + group_points_[ki]->unsetVisited(); + } + +#ifdef DEBUG_SEGMENT + std::ofstream of("curr_region_split2.g2"); + for (size_t kj=0; kj<connected.size(); ++kj) + { + of << "400 1 0 0" << std::endl; + of << connected[kj].size() << std::endl; + for (size_t kr=0; kr<connected[kj].size(); ++kr) + of << connected[kj][kr]->getPoint() << std::endl; + } +#endif + + if (connected.size() <= 1) + return; + + int max_num = 0; + int ix = -1; + for (size_t ki=0; ki<connected.size(); ++ki) + if ((int)connected[ki].size() > max_num) + { + max_num = (int)connected[ki].size(); + ix = (int)ki; + } + + if (ix >= 0) + { + group_points_.clear(); + group_points_ = connected[ix]; + + // Update bounding box and principal curvature summary + updateInfo(); + + for (size_t kj=0; kj<connected.size(); ++kj) + { + if ((int)kj == ix) + continue; + for (size_t kr=0; kr<connected[kj].size(); ++kr) + connected[kj][kr]->unsetRegion(); + separate_groups.push_back(connected[kj]); + } + } +} + +//=========================================================================== +shared_ptr<Plane> +RevEngRegion::planarComponent(Point vec, int min_point, int min_pt_reg, + double tol, double angtol, Point mainaxis[3], + vector<RevEngPoint*>& remaining, + vector<vector<RevEngPoint*> >& extracted) +//=========================================================================== +{ + shared_ptr<Plane> dummy_plane; + vector<vector<RevEngPoint*> > vec_pts(2); + int min_size = std::max(10, std::min(min_point, (int)group_points_.size()/20)); + vector<RevEngPoint*> pts_out; + for (size_t ki=0; ki<group_points_.size(); ++ki) + { + Point normal = group_points_[ki]->getLocFuncNormal(); + Point normal2 = group_points_[ki]->getTriangNormal(); + double ang = vec.angle(normal); + double ang2 = vec.angle(normal2); + if (ang < angtol || ang2 < angtol) + vec_pts[0].push_back(group_points_[ki]); + else if (M_PI-ang < angtol || M_PI-ang < angtol) + vec_pts[1].push_back(group_points_[ki]); + else + pts_out.push_back(group_points_[ki]); + } + + double eps = 1.0e-6; + double *seed = 0; + vector<vector<RevEngPoint*> > conn_groups; + for (int ka=0; ka<2; ++ka) + { + if ((int)vec_pts[ka].size() < min_size) + continue; + + // Check if the group can be represented by a plane + shared_ptr<Plane> plane = computePlane(vec_pts[ka], vec, mainaxis); + + vector<RevEngPoint*> inpt, outpt; + vector<pair<double, double> > dist_ang; + vector<double> parvals; + double maxdist, avdist; + int num_inside, num2_inside; + RevEngUtils::distToSurf(vec_pts[ka].begin(), vec_pts[ka].end(), plane, + tol, maxdist, avdist, num_inside, num2_inside, + inpt, outpt, parvals, dist_ang, angtol); + int sf_flag0 = defineSfFlag((int)vec_pts[ka].size(), 0, tol, num2_inside, + num_inside, avdist, false); + if (sf_flag0 < ACCURACY_POOR) + { + // Move points from out group if feasible + for (int kb=(int)pts_out.size()-1; kb>=0; --kb) + { + Vector3D xyz = pts_out[kb]->getPoint(); + Point pos(xyz[0], xyz[1], xyz[2]); + double upar, vpar, dist; + Point close; + plane->closestPoint(pos, upar, vpar, close, dist, eps, 0, seed); + if (dist <= tol) + { + vec_pts[ka].push_back(pts_out[kb]); + pts_out.erase(pts_out.begin()+kb); + } + } + + std::vector<RevEngPoint*> dummy; + connectedGroups(vec_pts[ka], conn_groups, false, dummy); + } + } + + // Identify largest group + if (conn_groups.size() == 0) + return dummy_plane; // No large planar component is found + + int max_group = 0; + int ix = -1; + for (size_t ki=0; ki<conn_groups.size(); ++ki) + { + if ((int)conn_groups[ki].size() > max_group) + { + max_group = (int)conn_groups[ki].size(); + ix = (int)ki; + } + } + + if (max_group < min_size) + return dummy_plane; // No large planar component is found + + // Update plane + shared_ptr<Plane> plane2 = computePlane(conn_groups[ix], vec, mainaxis); + +#ifdef DEBUG_PLANAR + std::ofstream of("planar_component.g2"); + writeRegionPoints(of); + shared_ptr<Plane> plane3(plane2->clone()); + double len = bbox_.low().dist(bbox_.high()); + plane3->setParameterBounds(-len, -len, len, len); + plane3->writeStandardHeader(of); + plane3->write(of); +#endif + + // Check angular behaviour of points + vector<RevEngPoint*> inpt2, outpt2; + vector<pair<double, double> > dist_ang2; + vector<double> parvals2; + double maxdist2, avdist2; + int num_inside2, num2_inside2; + RevEngUtils::distToSurf(conn_groups[ix].begin(), conn_groups[ix].end(), + plane2, tol, maxdist2, avdist2, num_inside2, num2_inside2, + inpt2, outpt2, parvals2, dist_ang2, angtol); + int sf_flag = defineSfFlag((int)conn_groups[ix].size(), 0, tol, num_inside2, + num2_inside2, avdist2, false); + if (sf_flag >= ACCURACY_POOR) + return dummy_plane; + + vector<RevEngPoint*> ang_out; + if (sf_flag > ACCURACY_OK) + { + // Check if any points should be removed + size_t num_in = conn_groups[ix].size(); + double dtol = std::min(0.5*tol, 1.5*avdist2); + for (size_t kr=0; kr<conn_groups[ix].size(); ++kr) + if (dist_ang2[kr].second > 2.0*angtol && dist_ang2[kr].first > dtol) + { + std::swap(conn_groups[ix][kr], conn_groups[ix][num_in-1]); + --num_in; + } + + if (num_in < conn_groups[ix].size()) + { + ang_out.insert(ang_out.end(), conn_groups[ix].begin()+num_in, + conn_groups[ix].end()); + conn_groups[ix].erase(conn_groups[ix].begin()+num_in, + conn_groups[ix].end()); +#ifdef DEBUG_PLANAR + std::ofstream ofa("ang_points_pc.g2"); + ofa << "400 1 0 4 50 50 155 255" << std::endl; + ofa << ang_out.size() << std::endl; + for (size_t kr=0; kr<ang_out.size(); ++kr) + ofa << ang_out[kr]->getPoint() << std::endl; +#endif + } + } + + if ((int)conn_groups[ix].size() < max_group) + return dummy_plane; + + // A result is reached. + vector<vector<RevEngPoint*> > connected; + vector<RevEngPoint*> dummy_inner; + connectedGroups(conn_groups[ix], connected, false, dummy_inner); + if (connected.size() > 1) + { + for (size_t kr=0; kr<connected.size(); ++kr) + for (size_t kh=kr+1; kh<connected.size(); ++kh) + if (connected[kh].size() > connected[kr].size()) + std::swap(connected[kh], connected[kr]); + conn_groups[ix] = connected[0]; + conn_groups.insert(conn_groups.end(), connected.begin()+1, + connected.end()); + } + + remaining = conn_groups[ix]; + for (size_t kr=0; kr<conn_groups.size(); ++kr) + { + if ((int)kr == ix) + continue; + extracted.push_back(conn_groups[kr]); + } + if (ang_out.size() > 0) + extracted.push_back(ang_out); + + vector<vector<RevEngPoint*> > connected2; + connectedGroups(pts_out, connected2, false, dummy_inner); + extracted.insert(extracted.end(), connected2.begin(), connected2.end()); + + return plane2; + } + + +//=========================================================================== +bool RevEngRegion::planarComponent(Point vec, int min_point, int min_pt_reg, + double tol, double angtol, Point mainaxis[3], + vector<shared_ptr<HedgeSurface> >& hedgesfs, + vector<vector<RevEngPoint*> >& out_groups, + vector<RevEngPoint*>& single_pts, + bool create_surface) +//=========================================================================== +{ + vector<vector<RevEngPoint*> > vec_pts(2); + vector<RevEngPoint*> remaining; + int min_size = std::max(10, std::min(min_point, (int)group_points_.size()/20)); + for (size_t ki=0; ki<group_points_.size(); ++ki) + { + Point normal = group_points_[ki]->getLocFuncNormal(); + Point normal2 = group_points_[ki]->getTriangNormal(); + double ang = vec.angle(normal); + double ang2 = vec.angle(normal2); + if (ang < angtol || ang2 < angtol) + vec_pts[0].push_back(group_points_[ki]); + else if (M_PI-ang < angtol || M_PI-ang < angtol) + vec_pts[1].push_back(group_points_[ki]); + else + remaining.push_back(group_points_[ki]); + } + + double eps = 1.0e-6; + double *seed = 0; + vector<vector<RevEngPoint*> > conn_groups; + for (int ka=0; ka<2; ++ka) + { + if ((int)vec_pts[ka].size() < min_size) + continue; + + // Check if the group can be represented by a plane + shared_ptr<Plane> plane = computePlane(vec_pts[ka], vec, mainaxis); + + vector<RevEngPoint*> inpt, outpt; + vector<pair<double, double> > dist_ang; + vector<double> parvals; + double maxdist, avdist; + int num_inside, num2_inside; + RevEngUtils::distToSurf(vec_pts[ka].begin(), vec_pts[ka].end(), + plane, tol, maxdist, avdist, num_inside, num2_inside, + inpt, outpt, parvals, dist_ang, -1); + if (num_inside > min_point && num_inside > (int)vec_pts[ka].size()/2 && + avdist <= tol) + { + // Move points from remaining group if feasible + for (size_t kr=0; kr<remaining.size(); ++kr) + { + Vector3D xyz = remaining[kr]->getPoint(); + Point pos(xyz[0], xyz[1], xyz[2]); + double upar, vpar, dist; + Point close; + plane->closestPoint(pos, upar, vpar, close, dist, eps, 0, seed); + if (dist < tol) + vec_pts[ka].push_back(remaining[kr]); + } + + std::vector<RevEngPoint*> dummy; + connectedGroups(vec_pts[ka], conn_groups, false, dummy); + + int stop_break = 1; + } + } + + // Identify largest group + if (conn_groups.size() == 0) + return false; // No large planar component is found + + int max_group = 0; + int ix = -1; + for (size_t ki=0; ki<conn_groups.size(); ++ki) + { + if ((int)conn_groups[ki].size() > max_group) + { + max_group = (int)conn_groups[ki].size(); + ix = (int)ki; + } + } + + if (max_group < min_size) + return false; // No large planar component is found + + // Extract identified points + if ((int)group_points_.size() > max_group) + { + for (size_t ki=0; ki<conn_groups[ix].size(); ++ki) + removePoint(conn_groups[ix][ki]); + std::swap(group_points_, conn_groups[ix]); + } + else + conn_groups[ix].clear(); + + // Update plane + shared_ptr<Plane> plane2 = computePlane(group_points_, vec, mainaxis); + +#ifdef DEBUG_PLANAR + std::ofstream of("planar_component.g2"); + writeRegionPoints(of); + shared_ptr<Plane> plane3(plane2->clone()); + double len = bbox_.low().dist(bbox_.high()); + plane3->setParameterBounds(-len, -len, len, len); + plane3->write(of); +#endif + + vector<RevEngPoint*> inpt2, outpt2; + vector<pair<double, double> > dist_ang2; + vector<double> parvals2; + double maxdist2, avdist2; + int num_inside2, num2_inside2; + RevEngUtils::distToSurf(group_points_.begin(), group_points_.end(), + plane2, tol, maxdist2, avdist2, num_inside2, num2_inside2, + inpt2, outpt2, parvals2, dist_ang2, angtol); + int sf_flag = defineSfFlag(0, tol, num_inside2, num2_inside2, + avdist2, false); + if (sf_flag > ACCURACY_OK && sf_flag < NOT_SET) + { + // Check if any points should be removed + vector<RevEngPoint*> ang_points; + double dtol = std::min(0.5*tol, 1.5*avdist2); + identifyAngPoints(dist_ang2, 2.0*angtol, dtol, ang_points); +#ifdef DEBUG_PLANAR + if (ang_points.size() > 0) + { + std::ofstream ofa("ang_points_pc.g2"); + ofa << "400 1 0 4 50 50 155 255" << std::endl; + ofa << ang_points.size() << std::endl; + for (size_t kr=0; kr<ang_points.size(); ++kr) + ofa << ang_points[kr]->getPoint() << std::endl; + } +#endif + + double del_frac = 0.01; + if ((double)ang_points.size() > del_frac*(double)group_points_.size()) + { + vector<vector<RevEngPoint*> > separate_groups; + extractSpesPoints(ang_points, separate_groups, true); + if (separate_groups.size() > 0) + { + updateInfo(tol, angtol); + inpt2.clear(); + outpt2.clear(); + parvals2.clear(); + dist_ang2.clear(); + plane2 = computePlane(group_points_, avnorm_, mainaxis); + RevEngUtils::distToSurf(group_points_.begin(), group_points_.end(), + plane2, tol, maxdist2, avdist2, + num_inside2, num2_inside2, + inpt2, outpt2, parvals2, dist_ang2, angtol); + } + for (size_t kr=0; kr<separate_groups.size(); ++kr) + { + if (separate_groups[kr].size() == 1) + { + separate_groups[kr][0]->unsetRegion(); + single_pts.push_back(separate_groups[kr][0]); + } + else + out_groups.push_back(separate_groups[kr]); + } + sf_flag = defineSfFlag(0, tol, num_inside2, num2_inside2, + avdist2, false); + } + } + + if (create_surface) + { + for (size_t ki=0; ki<group_points_.size(); ++ki) + { + group_points_[ki]->setPar(Vector2D(parvals2[2*ki],parvals2[2*ki+1])); + group_points_[ki]->setSurfaceDist(dist_ang2[ki].first, dist_ang2[ki].second); + } + setAccuracy(maxdist2, avdist2, num_inside2, num2_inside2); + shared_ptr<HedgeSurface> hedge(new HedgeSurface(plane2, this)); + setHedge(hedge.get()); + hedgesfs.push_back(hedge); + setSurfaceFlag(sf_flag); + } + updateInfo(tol, angtol); + + + // Split remaining points into connected components + if (conn_groups[ix].size() > 0) + { + shared_ptr<RevEngRegion> reg(new RevEngRegion(classification_type_, + edge_class_type_, + conn_groups[ix])); + vector<vector<RevEngPoint*> > connected; + reg->splitRegion(connected); + out_groups.push_back(reg->getPoints()); + for (size_t ki=0; ki<connected.size(); ++ki) + { + if (connected[ki].size() == 1) + { + connected[ki][0]->unsetRegion(); + single_pts.push_back(connected[ki][0]); + } + else + out_groups.push_back(connected[ki]); + } + } + + + return true; +} + +//=========================================================================== +shared_ptr<ElementarySurface> +RevEngRegion::helicalComponent(shared_ptr<Cylinder> cyl, double tol, + double angtol, int min_point, + int min_pt_reg, double avdist, int num_in2, + vector<pair<double,double> >& dist_ang, + vector<RevEngPoint*>& remaining, + vector<vector<RevEngPoint*> >& extracted, + double& maxd_out, double& avd_out, + int& num_in_out, int& num2_in_out, + vector<double>& parvals_out, + vector<pair<double,double> >& distang_out) +//=========================================================================== +{ + shared_ptr<ElementarySurface> dummy_surf; + // Compute rotated info + int num_in_lin1, num_in_cub1; + double avdist_lin1, avdist_cub1; + shared_ptr<Cone> cone; + analyseCylRotate(cyl, tol, avdist, num_in2, avdist_lin1, num_in_lin1, + avdist_cub1, num_in_cub1, cone); + + // Restrict to linear cases + double lfac = 1.2; + if (avdist_lin1 > lfac*avdist_cub1) + return dummy_surf; + + // Identify distant points + double eps = 1.0e-6; + double dlim = 2.0*avdist; + vector<RevEngPoint*> dist_pts; + vector<RevEngPoint*> in_pts; + BoundingBox bb(3); + for (size_t ki=0; ki<group_points_.size(); ++ki) + { + bool within = true; + Vector3D xyz = group_points_[ki]->getPoint(); + Point pos(xyz[0], xyz[1], xyz[2]); + if (cone.get()) + { + double upar, vpar, dist; + Point close; + cone->closestPoint(pos, upar, vpar, close, dist, eps); + if (dist > dlim) + within = false; + } + else + { + if (dist_ang[ki].first > dlim) + within = false; + } + + if (within) + { + in_pts.push_back(group_points_[ki]); + bb.addUnionWith(pos); + } + else + dist_pts.push_back(group_points_[ki]); + } + + if ((int)in_pts.size() < min_point) + return dummy_surf; + +#ifdef DEBUG_CYL + std::ofstream of("helical_split.g2"); + of << "400 1 0 4 0 0 255 255" << std::endl; + of << in_pts.size() << std::endl; + for (size_t ki=0; ki<in_pts.size(); ++ki) + of << in_pts[ki]->getPoint() << std::endl; + + of << "400 1 0 4 0 255 0 255" << std::endl; + of << dist_pts.size() << std::endl; + for (size_t ki=0; ki<dist_pts.size(); ++ki) + of << dist_pts[ki]->getPoint() << std::endl; +#endif + + // Check accuracy with respect to reduced point cloud + // For cylinder + double maxdist2, avdist2; + int num_inside2, num2_inside2=0; + vector<RevEngPoint*> inpt2, outpt2; + vector<double> parvals2; + vector<pair<double, double> > dist_ang2; + shared_ptr<Cylinder> cyl2 = computeCylinder(in_pts, tol); + RevEngUtils::distToSurf(in_pts.begin(), in_pts.end(), cyl2, + tol, maxdist2, avdist2, num_inside2, num2_inside2, + inpt2, outpt2, parvals2, dist_ang2, angtol); + int sf_flag2 = defineSfFlag((int)in_pts.size(), 0, tol, num_inside2, + num2_inside2, avdist2, true); + + // For cone + double len = bb.low().dist(bb.high()); + Point axis = cyl2->direction(); + Point Cx = cyl2->direction2(); + Point loc = cyl2->location(); + shared_ptr<Cone> cone2 = + RevEngUtils::coneWithAxis(in_pts, axis, Cx, loc, len); + + double maxdist3, avdist3; + int num_inside3, num2_inside3=0; + vector<RevEngPoint*> inpt3, outpt3; + vector<double> parvals3; + vector<pair<double, double> > dist_ang3; + RevEngUtils::distToSurf(in_pts.begin(), in_pts.end(), cone2, + tol, maxdist3, avdist3, num_inside3, num2_inside3, + inpt3, outpt3, parvals3, dist_ang3, angtol); + int sf_flag3 = defineSfFlag((int)in_pts.size(), 0, tol, num_inside3, + num2_inside3, avdist3, true); + + if (std::min(sf_flag2, sf_flag3) >= ACCURACY_POOR) + return dummy_surf; + + remaining = in_pts; + vector<vector<RevEngPoint*> > connected; + vector<RevEngPoint*> dummy_inner; + connectedGroups(dist_pts, connected, false, dummy_inner); + extracted = connected; + + if (sf_flag2 < sf_flag3 || + (sf_flag2 == sf_flag3 && + (avdist2 < avdist3 || num_inside2 > num_inside3))) + { + maxd_out = maxdist2; + avd_out = avdist2; + num_in_out = num_inside2; + num2_in_out = num2_inside2; + parvals_out = parvals2; + distang_out = dist_ang2; + return cyl2; + } + else + { + maxd_out = maxdist3; + avd_out = avdist3; + num_in_out = num_inside3; + num2_in_out = num2_inside3; + parvals_out = parvals3; + distang_out = dist_ang3; + return cone2; + } +} + + +//=========================================================================== +bool RevEngRegion::defineHelicalInfo(shared_ptr<Cylinder> cyl, double tol, + double angtol, int min_point, + int min_pt_reg, double avdist, + int num_in1, int num_in2, + vector<pair<double,double> >& dist_ang, + vector<shared_ptr<HedgeSurface> >& hedgesfs, + vector<vector<RevEngPoint*> >& out_groups, + vector<RevEngPoint*>& single_pts) +//=========================================================================== +{ + // Compute rotated info + int num_in_lin1, num_in_cub1; + double avdist_lin1, avdist_cub1; + shared_ptr<Cone> cone; + analyseCylRotate(cyl, tol, avdist, num_in2, avdist_lin1, num_in_lin1, + avdist_cub1, num_in_cub1, cone); + + // Restrict to linear cases + double lfac = 1.2; + if (avdist_lin1 > lfac*avdist_cub1) + return false; + + // Identify distant points + double dlim = 2.0*avdist; + vector<RevEngPoint*> dist_pts; + vector<RevEngPoint*> remaining; + for (size_t ki=0; ki<group_points_.size(); ++ki) + { + if (dist_ang[ki].first > dlim) + dist_pts.push_back(group_points_[ki]); + else + remaining.push_back(group_points_[ki]); + } + + // Check accuracy with respect to reduced point cloud + double maxdist2, avdist2; + int num_inside2, num2_inside2=0; + vector<RevEngPoint*> inpt2, outpt2; + vector<double> parvals2; + vector<pair<double, double> > dist_ang2; + shared_ptr<Cylinder> cyl2 = computeCylinder(remaining, tol); + RevEngUtils::distToSurf(remaining.begin(), remaining.end(), + cyl2, tol, maxdist2, avdist2, num_inside2, num2_inside2, + inpt2, outpt2, parvals2, dist_ang2, angtol); + + // Check level of change + double ang = cyl->direction().angle(cyl2->direction()); + ang = std::min(ang, M_PI-ang); + double distfac = 0.5; + double angmin = 0.1*M_PI; + if (ang > angmin && avdist2 > tol && + (double)num2_inside2/(double)num_in2 > distfac) + return false; // Not likely that the computed cylinder is a good representation + + int nfac = 2; + if (num2_inside2 < nfac*num_inside2 && (num_inside2 < (int)remaining.size()/2 || + avdist2 > tol)) + return false; // Probably not a helical surface and not sufficient accuracy for + // a cylinder + +#ifdef DEBUG_CYL + std::ofstream of("helical_split.g2"); + of << "400 1 0 4 0 0 255 255" << std::endl; + of << remaining.size() << std::endl; + for (size_t ki=0; ki<remaining.size(); ++ki) + of << remaining[ki]->getPoint() << std::endl; + + of << "400 1 0 4 0 255 0 255" << std::endl; + of << dist_pts.size() << std::endl; + for (size_t ki=0; ki<dist_pts.size(); ++ki) + of << dist_pts[ki]->getPoint() << std::endl; +#endif + // Set info to remaining + for (size_t ki=0; ki<remaining.size(); ++ki) + { + remaining[ki]->setPar(Vector2D(parvals2[2*ki],parvals2[2*ki+1])); + remaining[ki]->setSurfaceDist(dist_ang2[ki].first, dist_ang2[ki].second); + } + std::swap(group_points_, remaining); + updateInfo(tol, angtol); + + // Make sure that the remaining points are connected + vector<vector<RevEngPoint*> > separate_groups; + splitRegion(separate_groups); + if (separate_groups.size() > 0) + { + // Recompute + cyl2 = computeCylinder(group_points_, tol); + parvals2.clear(); + inpt2.clear(); + outpt2.clear(); + + RevEngUtils::distToSurf(group_points_.begin(), group_points_.end(), + cyl2, tol, maxdist2, avdist2, + num_inside2, num2_inside2, + inpt2, outpt2, parvals2, dist_ang2, angtol); + for (size_t ki=0; ki<group_points_.size(); ++ki) + { + group_points_[ki]->setPar(Vector2D(parvals2[2*ki],parvals2[2*ki+1])); + group_points_[ki]->setSurfaceDist(dist_ang2[ki].first, dist_ang2[ki].second); + } + updateInfo(tol, angtol); + } + + for (size_t ki=0; ki<separate_groups.size(); ++ki) + { + if (separate_groups[ki].size() == 1) + { + separate_groups[ki][0]->unsetRegion(); + single_pts.push_back(separate_groups[ki][0]); + } + else + out_groups.push_back(separate_groups[ki]); + } + + // Surface flag + int sf_flag = defineSfFlag(0, tol, num_inside2, num2_inside2, + avdist2, true); + + if (sf_flag < ACCURACY_POOR) + { + setAccuracy(maxdist2, avdist2, num_inside2, num2_inside2); + shared_ptr<HedgeSurface> hedge(new HedgeSurface(cyl2, this)); + setHedge(hedge.get()); + hedgesfs.push_back(hedge); + setSurfaceFlag(sf_flag); + } + else if (num2_inside2 >= nfac*num_inside2) + { + shared_ptr<SplineCurve> dummy; + sweep_ = shared_ptr<SweepData>(new SweepData(3, dummy, cyl2->location(), + cyl2->direction(), maxdist2, + avdist2, num_inside2, + cyl2->getRadius())); + } + + setBaseSf(cyl2, maxdist2, avdist2, num_inside2, num2_inside2); + + // Split remaining points into connected components + vector<vector<RevEngPoint*> > connected; + std::vector<RevEngPoint*> dummy; + connectedGroups(dist_pts, connected, false, dummy); + + for (size_t ki=0; ki<connected.size(); ++ki) + { + if (connected[ki].size() == 1) + { + connected[ki][0]->unsetRegion(); + single_pts.push_back(connected[ki][0]); + } + else + out_groups.push_back(connected[ki]); + } + + return true; +} + +//=========================================================================== +void RevEngRegion::setAssociatedSurface(shared_ptr<ParamSurface>& surf, + double tol, double angtol, + int min_pt_reg, + shared_ptr<HedgeSurface>& hedge) +//=========================================================================== +{ + // Compute accuracy + double maxdist, avdist; + int num_in, num2_in; + vector<RevEngPoint*> inpt, outpt; + vector<pair<double, double> > dist_ang; + vector<double> parvals; + RevEngUtils::distToSurf(group_points_.begin(), group_points_.end(), + surf, tol, maxdist, avdist, num_in, num2_in, + inpt, outpt, parvals, dist_ang, angtol); + + bool cyllike = (surf->instanceType() == Class_Cylinder || + surf->instanceType() == Class_Cone); + int sf_flag = defineSfFlag(0, tol, num_in, num2_in, avdist, cyllike); + + for (size_t kh=0; kh<group_points_.size(); ++kh) + { + group_points_[kh]->setPar(Vector2D(parvals[2*kh],parvals[2*kh+1])); + group_points_[kh]->setSurfaceDist(dist_ang[kh].first, dist_ang[kh].second); + } + setAccuracy(maxdist, avdist, num_in, num2_in); + hedge = shared_ptr<HedgeSurface>(new HedgeSurface(surf, this)); + setHedge(hedge.get()); + setSurfaceFlag(sf_flag); +} + +//=========================================================================== +void RevEngRegion::extractOutPoints(int dir, double tol, double angtol, + double angtol2, + vector<vector<RevEngPoint*> >& out_groups) +//=========================================================================== +{ + // Compute real domain + double dom[4]; + int ka; + int num_pt = (int)group_points_.size(); + double dist, ang; + for (ka=0; ka<num_pt; ++ka) + { + Vector2D uv = group_points_[ka]->getPar(); + group_points_[ka]->getSurfaceDist(dist, ang); + if (ang <= angtol2) + { + dom[0] = dom[1] = uv[0]; + dom[2] = dom[3] = uv[1]; + break; + } + } + for (; ka<num_pt; ++ka) + { + Vector2D uv = group_points_[ka]->getPar(); + group_points_[ka]->getSurfaceDist(dist, ang); + if (ang > angtol2) + continue; + dom[0] = std::min(dom[0], uv[0]); + dom[1] = std::max(dom[1], uv[0]); + dom[2] = std::min(dom[2], uv[1]); + dom[3] = std::max(dom[3], uv[1]); + } + + vector<RevEngPoint*> out1, out2, remain; + for (ka=0; ka<num_pt; ++ka) + { + Vector2D uv = group_points_[ka]->getPar(); + if (uv[dir] < dom[2*dir]) + out1.push_back(group_points_[ka]); + else if (uv[dir] > dom[2*dir+1]) + out2.push_back(group_points_[ka]); + else + remain.push_back(group_points_[ka]); + } + + if (remain.size() < group_points_.size()) + { + std::swap(remain, group_points_); + updateInfo(tol, angtol); + + if (out1.size() > 0) + { + vector<vector<RevEngPoint*> > con; + vector<RevEngPoint*> dummy; + connectedGroups(out1, con, false, dummy); + for (size_t ki=0; ki<con.size(); ++ki) + { + for (size_t kj=0; kj<con[ki].size(); ++kj) + con[ki][kj]->unsetRegion(); + } + out_groups.insert(out_groups.end(), con.begin(), con.end()); + } + + if (out2.size() > 0) + { + vector<vector<RevEngPoint*> > con; + vector<RevEngPoint*> dummy; + connectedGroups(out2, con, false, dummy); + for (size_t ki=0; ki<con.size(); ++ki) + { + for (size_t kj=0; kj<con[ki].size(); ++kj) + con[ki][kj]->unsetRegion(); + } + out_groups.insert(out_groups.end(), con.begin(), con.end()); + } + } + } + +//=========================================================================== +int RevEngRegion::defineSfFlag(int min_point, double tol, int num_in, + int num_in2, double avd, bool type_cyl) +//=========================================================================== +{ + int sf_flag = NOT_SET; + double fac = 2.0; + bool OK = accuracyOK(0, tol, num_in, avd); + int nfac = 2; + if (OK) + sf_flag = ACCURACY_OK; + else + { + OK = accuracyOK(min_point, tol, num_in2, avd); + if (OK) + sf_flag = ANGULAR_DEVIATION; + else + { + OK = accuracyOK(min_point, fac*tol, num_in2, avd); + if (OK) + sf_flag = ACCURACY_POOR; + } + } + + if ((sf_flag == ANGULAR_DEVIATION || + (num_in2 >= nfac*num_in && sf_flag < ACCURACY_POOR)) && type_cyl) + sf_flag = PROBABLE_HELIX; + + return sf_flag; +} + +//=========================================================================== +int RevEngRegion::defineSfFlag(int num_points, int min_point, double tol, int num_in, + int num_in2, double avd, bool type_cyl) +//=========================================================================== +{ + int sf_flag = NOT_SET; + double fac = 2.0; + bool OK = accuracyOK(num_points, min_point, tol, num_in, avd); + int nfac = 2; + if (OK) + sf_flag = ACCURACY_OK; + else + { + OK = accuracyOK(num_points, min_point, tol, num_in2, avd); + if (OK) + sf_flag = ANGULAR_DEVIATION; + else + { + OK = accuracyOK(num_points, min_point, fac*tol, num_in2, avd); + if (OK) + sf_flag = ACCURACY_POOR; + } + } + + if ((sf_flag == ANGULAR_DEVIATION || + (num_in2 >= nfac*num_in && sf_flag < ACCURACY_POOR)) && type_cyl) + sf_flag = PROBABLE_HELIX; + + return sf_flag; +} + +//=========================================================================== +void RevEngRegion::updateInfo(double tol, double angtol) +//=========================================================================== +{ + maxk2_ = std::numeric_limits<double>::lowest(); + mink2_ = std::numeric_limits<double>::max(); + maxk1_ = std::numeric_limits<double>::lowest(); + mink1_ = std::numeric_limits<double>::max(); + MAH_ = MAK_ = avH_ = avK_ = 0.0; + bbox_ = BoundingBox(3); + double fac = 1.0/(double)group_points_.size(); + for (size_t kj=0; kj<group_points_.size(); ++kj) + { + double k1 = group_points_[kj]->minPrincipalCurvature(); + double k2 = group_points_[kj]->maxPrincipalCurvature(); + double H = group_points_[kj]->meanCurvature(); + double K = group_points_[kj]->GaussCurvature(); + mink1_ = std::min(mink1_, fabs(k1)); + maxk1_ = std::max(maxk1_, fabs(k1)); + mink2_ = std::min(mink2_, fabs(k2)); + maxk2_ = std::max(maxk2_, fabs(k2)); + avH_ += fac*H; + avK_ += fac*K; + MAH_ += fac*fabs(H); + MAK_ += fac*fabs(K); + Vector3D point = group_points_[kj]->getPoint(); + Point point2(point[0], point[1], point[2]); + bbox_.addUnionWith(point2); + } + + if (group_points_.size() > 0) + { + normalcone_ = DirectionCone(group_points_[0]->getLocFuncNormal()); + normalcone2_ = DirectionCone(group_points_[0]->getTriangNormal()); + avnorm_ = Point(0.0, 0.0, 0.0); + avnorm2_ = Point(0.0, 0.0, 0.0); + for (size_t kj=0; kj<group_points_.size(); ++kj) + { + Point norm = group_points_[kj]->getLocFuncNormal(); + normalcone_.addUnionWith(norm); + avnorm_ += fac*norm; + Point norm2 = group_points_[kj]->getTriangNormal(); + normalcone2_.addUnionWith(norm2); + avnorm2_ += fac*norm2; + } + // (void)avnorm_.normalize_checked(); + // (void)avnorm2_.normalize_checked(); + + double anglim = 0.2; + if (normalcone_.angle() <= anglim) + frac_norm_in_ = 1.0; + else + { + int nmb_in = 0; + for (size_t kr=0; kr<group_points_.size(); ++kr) + { + Point normal = group_points_[kr]->getLocFuncNormal(); + if (avnorm_.angle(normal) <= anglim) + nmb_in++; + } + frac_norm_in_ = (double)nmb_in/(double)group_points_.size(); + } + + if (normalcone2_.angle() <= anglim) + frac_norm_in2_ = 1.0; + else + { + int nmb_in = 0; + for (size_t kr=0; kr<group_points_.size(); ++kr) + { + Point normal = group_points_[kr]->getTriangNormal(); + if (avnorm2_.angle(normal) <= anglim) + nmb_in++; + } + frac_norm_in2_ = (double)nmb_in/(double)group_points_.size(); + } + } + + if (hasSurface() && group_points_.size() > 0) + { + if (tol > 0.0) + { + maxdist_ = avdist_ = 0.0; + num_inside_ = num_inside2_ = 0; + } + Vector2D par = group_points_[0]->getPar(); + domain_[0] = domain_[1] = par[0]; + domain_[2] = domain_[3] = par[1]; + for (size_t kj=0; kj<group_points_.size(); ++kj) + { + Vector2D par = group_points_[kj]->getPar(); + domain_[0] = std::min(domain_[0], par[0]); + domain_[1] = std::max(domain_[1], par[0]); + domain_[2] = std::min(domain_[2], par[1]); + domain_[3] = std::max(domain_[3], par[1]); + if (tol > 0.0) + { + double dist, ang; + group_points_[kj]->getSurfaceDist(dist, ang); + maxdist_ = std::max(maxdist_, dist); + avdist_ += fac*dist; + if (dist <= tol) + { + num_inside2_++; + if (ang <= angtol) + num_inside_++; + } + } + } + if (tol > 0.0) + { + shared_ptr<ParamSurface> surf = getSurface(0)->surface(); + bool cyllike = (surf->instanceType() == Class_Cylinder || + surf->instanceType() == Class_Cone); + surfflag_ = defineSfFlag(0, tol, num_inside_, num_inside2_, avdist_, + cyllike); + } + } +} + +//=========================================================================== +void RevEngRegion::addPoint(RevEngPoint* point) +//=========================================================================== +{ +#ifdef DEBUG_CHECK + if (std::find(group_points_.begin(), group_points_.end(), point) != group_points_.end()) + std::cout << "addPoint: point exists already. " << point << std::endl; +#endif + int nmb = (int)group_points_.size(); + group_points_.push_back(point); + point->setRegion(this); + Vector3D point2 = point->getPoint(); + Point point3(point2[0], point2[1], point2[2]); + bbox_.addUnionWith(point3); + Point norm = point->getLocFuncNormal(); + normalcone_.addUnionWith(norm); + Point norm2 = point->getTriangNormal(); + normalcone2_.addUnionWith(norm2); + double k1 = point->minPrincipalCurvature(); + double k2 = point->maxPrincipalCurvature(); + mink1_ = std::min(mink1_, fabs(k1)); + maxk1_ = std::max(maxk1_, fabs(k1)); + mink2_ = std::min(mink2_, fabs(k2)); + maxk2_ = std::max(maxk2_, fabs(k2)); + avnorm_ = (nmb*avnorm_ + norm)/(double)(nmb+1); + double H = point->meanCurvature(); + double K = point->GaussCurvature(); + avH_ = (nmb*avH_ + H)/(double)(nmb+1); + avK_ = (nmb*avK_ + K)/(double)(nmb+1); + MAH_ = (nmb*MAH_ + fabs(H))/(double)(nmb+1); + MAK_ = (nmb*MAK_ + fabs(K))/(double)(nmb+1); + + if (hasSurface()) + { + Vector2D par = point->getPar(); + domain_[0] = std::min(domain_[0], par[0]); + domain_[1] = std::max(domain_[1], par[0]); + domain_[2] = std::min(domain_[2], par[1]); + domain_[3] = std::max(domain_[3], par[1]); + } + +} + +//=========================================================================== +void RevEngRegion::computeDomain() +//=========================================================================== +{ + if (hasSurface() && group_points_.size() > 0) + { + Vector2D par = group_points_[0]->getPar(); + domain_[0] = domain_[1] = par[0]; + domain_[2] = domain_[3] = par[1]; + for (size_t kj=1; kj<group_points_.size(); ++kj) + { + Vector2D par = group_points_[kj]->getPar(); + domain_[0] = std::min(domain_[0], par[0]); + domain_[1] = std::max(domain_[1], par[0]); + domain_[2] = std::min(domain_[2], par[1]); + domain_[3] = std::max(domain_[3], par[1]); + } + } +} + +//=========================================================================== +void RevEngRegion::removePoint(RevEngPoint* point) +//=========================================================================== +{ + auto found = std::find(group_points_.begin(), group_points_.end(), point); + if (found != group_points_.end()) + { + std::swap(*found, group_points_[group_points_.size()-1]); + group_points_.pop_back(); + } + // for (size_t ki=0; ki<group_points_.size(); ++ki) + // if (group_points_[ki] == point) + // { + // group_points_.erase(group_points_.begin()+ki); + // break; + // } +} + +//=========================================================================== +void RevEngRegion::updateWithPointsInOut(vector<RevEngPoint*>& points_out, + vector<RevEngPoint*>& points_in, + double tol, double angtol) +//=========================================================================== +{ + for (size_t ki=0; ki<points_out.size(); ++ki) + { + removePoint(points_out[ki]); + points_out[ki]->unsetRegion(); + } + + shared_ptr<ParamSurface> surf; + bool cyllike = false; + if (hasSurface()) + { + surf = getSurface(0)->surface(); + cyllike = (surf->instanceType() == Class_Cylinder || + surf->instanceType() == Class_Cone); + double maxd, avd; + int num_inside, num2_inside; + vector<RevEngPoint*> inpt, outpt; + vector<pair<double, double> > dist_ang; + vector<double> parvals; + RevEngUtils::distToSurf(points_in.begin(), points_in.end(), + surf, tol, maxd, avd, num_inside, num2_inside, + inpt, outpt, parvals, dist_ang, angtol); + for (size_t ki=0; ki<points_in.size(); ++ki) + { + points_in[ki]->setPar(Vector2D(parvals[2*ki],parvals[2*ki+1])); + points_in[ki]->setSurfaceDist(dist_ang[ki].first, dist_ang[ki].second); + } + } + for (size_t ki=0; ki<points_in.size(); ++ki) + addPoint(points_in[ki]); + + updateInfo(tol, angtol); + int sf_flag = NOT_SET; + if (hasSurface()) + { + double maxd2, avd2; + int num_in2, num2_in2; + getAccuracy(maxd2, avd2, num_in2, num2_in2); + sf_flag = defineSfFlag(0, tol, num_in2, num2_in2, avd2, cyllike); + setSurfaceFlag(sf_flag); + } +} + +//=========================================================================== +void RevEngRegion::sortBlendPoints(vector<RevEngPoint*>& points, + vector<shared_ptr<CurveOnSurface> >& cvs, + double distance, bool in_blend, + vector<RevEngPoint*>& blend_points) +//=========================================================================== +{ + int num_points = (int)points.size(); + for (int ki=num_points-1; ki>=0; --ki) + { + double tpar, dist; + Point close; + Vector3D xyz = points[ki]->getPoint(); + Point pt(xyz[0], xyz[1], xyz[2]); + //int ix = -1; + for (size_t kj=0; kj<cvs.size(); ++kj) + { + cvs[kj]->closestPoint(pt, cvs[kj]->startparam(), cvs[kj]->endparam(), + tpar, close, dist); + if ((in_blend && dist < distance) || + (in_blend == false && dist >= distance)) + { + blend_points.push_back(points[ki]); + std::swap(points[ki],points[num_points-1]); + --num_points; + } + } + } + + if (num_points < (int)points.size()) + points.erase(points.begin()+num_points, points.end()); +} + +//=========================================================================== +void RevEngRegion::sortBlendPoints(vector<RevEngPoint*>& points, + vector<shared_ptr<CurveOnSurface> >& cvs, + double distance, RevEngRegion* other, + vector<RevEngPoint*>& blend_points1, + vector<RevEngPoint*>& blend_points2) +//=========================================================================== +{ + if ((!hasSurface()) || (!other->hasSurface())) + return; // Not as expected + + double eps = 1.0e-6; + int num_points = (int)points.size(); + shared_ptr<ParamSurface> surf1 = getSurface(0)->surface(); + shared_ptr<ParamSurface> surf2 = other->getSurface(0)->surface(); + double upar1, upar2, vpar1, vpar2, dist1, dist2; + Point close1, close2; + for (int ki=num_points-1; ki>=0; --ki) + { + double tpar, dist; + Point close; + Vector3D xyz = points[ki]->getPoint(); + Point pt(xyz[0], xyz[1], xyz[2]); + int ix = -1; + for (size_t kj=0; kj<cvs.size(); ++kj) + { + cvs[kj]->closestPoint(pt, cvs[kj]->startparam(), cvs[kj]->endparam(), + tpar, close, dist); + if (dist >= distance) + { + // Check which adjacent region the point belongs to + surf1->closestPoint(pt, upar1, vpar1, close1, dist1, eps); + surf2->closestPoint(pt, upar2, vpar2, close2, dist2, eps); + if (dist1 <= dist2) + blend_points1.push_back(points[ki]); + else + blend_points2.push_back(points[ki]); + std::swap(points[ki],points[num_points-1]); + --num_points; + } + } + } + + if (num_points < (int)points.size()) + points.erase(points.begin()+num_points, points.end()); +} + + +//=========================================================================== +void RevEngRegion::setRegionAdjacency() +//=========================================================================== +{ + for (size_t ki=0; ki<group_points_.size(); ++ki) + { + vector<ftSamplePoint*> next = group_points_[ki]->getNeighbours(); + for (size_t kj=0; kj<next.size(); ++kj) + { + RevEngPoint *curr = dynamic_cast<RevEngPoint*>(next[kj]); + RevEngRegion *adj_reg = curr->region(); + if (adj_reg == this) + continue; + if (adj_reg) + { + adj_reg->addAdjacentRegion(this); + addAdjacentRegion(adj_reg); + } + } + } +} + +//=========================================================================== +void RevEngRegion::updateRegionAdjacency() +//=========================================================================== +{ + for (auto it=adjacent_regions_.begin(); it!=adjacent_regions_.end(); ++it) + (*it)->removeAdjacentRegion(this); + adjacent_regions_.clear(); + + setRegionAdjacency(); +} + +struct integrate_info +{ + RevEngRegion *adjacent; + int nmb_pt_adj; + double maxd, avd, maxd_adj, avd_adj; + int nmb_in, nmb_in_adj; + double min_ang, max_ang, min_dist, max_dist; + bool outlier; + + integrate_info() + { + adjacent = 0; + nmb_pt_adj = nmb_in = nmb_in_adj = 0; + maxd = avd = maxd_adj = avd_adj = 0.0; + min_ang = max_ang = min_dist = max_dist = -1.0; + outlier = false; + } + + void setAdjacent(RevEngRegion* adj) + { + adjacent = adj; + } + + void setOutlier() + { + outlier = true; + } + + void setNmbAdj(int nmb) + { + nmb_pt_adj = nmb; + } + + void setAccuracy(double maxd1, double avd1, int nmb_in1, double maxd2, + double avd2, int nmb_in2) + { + maxd = maxd1; + avd = avd1; + nmb_in = nmb_in1; + maxd_adj = maxd2; + avd_adj = avd2; + nmb_in_adj = nmb_in2; + } + + void setMinMax(double min_a, double max_a, double min_d, double max_d) + { + min_ang = min_a; + max_ang = max_a; + min_dist = min_d; + max_dist = max_d; + } +}; + +//=========================================================================== +bool RevEngRegion::integrateInAdjacent(double mean_edge_len, int min_next, + int max_next, double tol, double angtol, + int max_nmb_outlier, + RevEngRegion* taboo) +//=========================================================================== +{ + // if (adjacent_regions_.size() != 1) + // return false; // To be removed + + if ((int)group_points_.size() > max_next/2) + return false; + +#ifdef DEBUG_INTEGRATE + std::ofstream of("curr_integrate.g2"); + of << "400 1 0 4 0 255 0 255" << std::endl; + of << group_points_.size() << std::endl; + for (size_t kh=0; kh<group_points_.size(); ++kh) + of << group_points_[kh]->getPoint() << std::endl; +#endif + size_t kj=0; + double local_len = group_points_[0]->getMeanEdgLen(10.0*mean_edge_len); + double radius = 3.0*(local_len + mean_edge_len); + radius = std::min(radius, 20.0*mean_edge_len); + size_t adjsize = adjacent_regions_.size(); + vector<integrate_info> info(adjsize); + + for (auto it=adjacent_regions_.begin(); it!=adjacent_regions_.end(); ++it, ++kj) + info[kj].setAdjacent(*it); + + if ((int)group_points_.size() <= max_nmb_outlier) + { + // Simplified test + vector<RevEngRegion*> adj_reg; + vector<pair<double,double> > adj_info; + double lentol = 2.0*mean_edge_len; + for (size_t ki=0; ki<group_points_.size(); ++ki) + { + vector<RevEngRegion*> pt_adj_reg; + vector<RevEngPoint*> pt_adj_pt; + group_points_[ki]->getAdjInfo(mean_edge_len, pt_adj_reg, pt_adj_pt); + Point monge1 = group_points_[ki]->getLocFuncNormal(); + for (size_t kj=0; kj<pt_adj_pt.size(); ++kj) + { + if (pt_adj_reg[kj] == this) + continue; + double len = group_points_[ki]->pntDist(pt_adj_pt[kj]); + if (len > lentol) + continue; + Point monge2 = pt_adj_pt[kj]->getLocFuncNormal(); + if (monge1*monge2 < 0.0 || monge1.angle(monge2) > angtol) + continue; + adj_reg.push_back(pt_adj_reg[kj]); + adj_info.push_back(std::make_pair(len, monge1.angle(monge2))); + } + } + + for (size_t kj=0; kj<info.size(); ++kj) + { + RevEngRegion *reg2 = info[kj].adjacent; + for (size_t ki=0; ki<adj_reg.size(); ++ki) + { + if (adj_reg[ki] == reg2) + { + if (info[kj].max_dist < 0.0) + { + info[kj].min_dist = info[kj].max_dist = adj_info[ki].first; + info[kj].min_ang = info[kj].max_ang = adj_info[ki].second; + } + else + { + info[kj].min_dist = std::min(info[kj].min_dist,adj_info[ki].first); + info[kj].max_dist = std::max(info[kj].max_dist,adj_info[ki].first); + info[kj].min_ang = std::min(info[kj].min_ang,adj_info[ki].second); + info[kj].max_ang = std::max(info[kj].max_ang,adj_info[ki].second); + } + } + } + } + } + + kj = 0; + for (auto it=adjacent_regions_.begin(); it!=adjacent_regions_.end(); ++it, ++kj) + { + double maxd1, maxd2, avd1, avd2; + maxd1 = maxd2 = avd1 = avd2 = std::numeric_limits<double>::max(); + int nmb_in1 = 0, nmb_in1_2 = 0, nmb_in2 = 0; + bool local_approx = (info[kj].max_dist < 0.0); + bool outlier = false; + int nmb_pt_adj; + bool computed = computeIntegrateInfo(group_points_, *it, tol, angtol, radius, + local_approx, min_next, max_next, max_nmb_outlier, + outlier, nmb_pt_adj, maxd2, avd2, nmb_in2, maxd1, + avd1, nmb_in1, nmb_in1_2); + info[kj].setNmbAdj(nmb_pt_adj); + if (outlier) + info[kj].setOutlier(); + if (!computed) + continue; + // shared_ptr<ParamSurface> surf; + // if ((*it)->hasSurface()) + // { + // surf = (*it)->getSurface(0)->surface(); + // (*it)->getAccuracy(maxd1, avd1, nmb_in1); + // } + // else if ((*it)->hasBaseSf()) + // (*it)->getBase(surf, maxd1, avd1, nmb_in1); + + // if (surf.get()) + // { + // // Fetch accuracy of current surface + // info[kj].setNmbAdj((*it)->numPoints()); + + // // Check accuracy of new points + // vector<RevEngPoint*> in2, out2; + // vector<pair<double,double> > dist_ang2; + // vector<double> parvals2; + // RevEngUtils::distToSurf(group_points_.begin(), group_points_.end(), + // surf, tol, maxd2, avd2, nmb_in2, in2, out2, + // parvals2, dist_ang2, angtol); + // } + // else if (info[kj].max_dist < 0.0) + // { + // // Fetch nearby points + // vector<RevEngPoint*> nearpts; + // if ((*it)->numPoints() < min_next) + // nearpts.insert(nearpts.end(), (*it)->pointsBegin(), (*it)->pointsEnd()); + // else + // { + // for (size_t ki=0; ki<group_points_.size(); ++ki) + // { + // nearpts.clear(); + // group_points_[ki]->fetchClosePoints2(radius, min_next, + // max_next-(int)group_points_.size(), + // nearpts, *it); + // if (nearpts.size() > max_nmb_outlier) + // break; + // } + // } + // size_t nearnmb = nearpts.size(); + // info[kj].setNmbAdj((int)nearnmb); + // if (((int)(nearnmb+group_points_.size()) <= max_nmb_outlier) || + // ((int)nearnmb <= max_nmb_outlier && (*it)->numPoints() > min_next)) + // { + // if ((int)group_points_.size() <= max_nmb_outlier) + // info[kj].setOutlier(); + // continue; + // } + + // nearpts.insert(nearpts.end(), group_points_.begin(), group_points_.end()); + // BoundingBox bbox = bbox_; + // for (size_t ki=0; ki<nearnmb; ++ki) + // { + // Vector3D xyz = nearpts[ki]->getPoint(); + // Point xyz2(xyz[0], xyz[1], xyz[2]); + // bbox.addUnionWith(xyz2); + // } + // surf = surfApprox(nearpts, bbox); + + // // Check accuracy + // vector<RevEngPoint*> in1, in2, out1, out2; + // vector<pair<double,double> > dist_ang1, dist_ang2; + // vector<double> parvals1, parvals2; + // RevEngUtils::distToSurf(nearpts.begin(), nearpts.begin()+nearnmb, surf, + // tol, maxd1, avd1, nmb_in1, in1, out1, + // parvals1, dist_ang1, angtol); + // RevEngUtils::distToSurf(nearpts.begin()+nearnmb, nearpts.end(), surf, + // tol, maxd2, avd2, nmb_in2, in2, out2, + // parvals2, dist_ang2, angtol); + // } +#ifdef DEBUG_INTEGRATE + int num = (*it)->numPoints(); + of << "400 1 0 4 255 0 0 255" << std::endl; + of << num << std::endl; + for (int ka=0; ka<num; ++ka) + of << (*it)->getPoint(ka)->getPoint() << std::endl; + + // if (surf.get()) + // { + // surf->writeStandardHeader(of); + // surf->write(of); + // } +#endif + info[kj].setAccuracy(maxd2, avd2, nmb_in2, maxd1, avd1, nmb_in1); + } + + // Select adjacent + bool outlier = true; + int ix = -1; + double score = 0.0; + int num = (int)group_points_.size(); + for (size_t kj=0; kj<info.size(); ++kj) + { + if (!info[kj].outlier) + outlier = false; + if (taboo && info[kj].adjacent == taboo /*&& info.size()>1*/) + continue; + if (prev_region_ && info[kj].adjacent == prev_region_ && info.size()>1) + continue; + if (info[kj].avd > tol || (info[kj].nmb_in < num/2 && info[kj].maxd > tol)) + continue; + if (info[kj].adjacent->hasAssociatedBlend()) + continue; // Not to be extended + double frac1 = (double)info[kj].nmb_in/(double)num; + double frac2 = (double)info[kj].nmb_in_adj/(double)info[kj].nmb_pt_adj; + if (frac1 < 0.9*frac2 && info[kj].maxd > tol) + continue; + double avH = avH_*info[kj].adjacent->avH_; + double avK = avK_*info[kj].adjacent->avK_; + double curr_score = (tol/std::max(1.0e-6, info[kj].avd)) + /* frac2/frac1 +*/ + (info[kj].adjacent->hasSurface()) + (avH > 0.0) + (avK > 0.0); + if (curr_score > score) + { + ix = (int)kj; + score = curr_score; + } + } + + if (ix < 0 && (!outlier)) + { + double div = std::numeric_limits<double>::max(); + for (size_t kj=0; kj<info.size(); ++kj) + { + if (info[kj].max_dist < 0) + continue; + if (taboo && info[kj].adjacent == taboo /*&& info.size()>1*/) + continue; + if (prev_region_ && info[kj].adjacent == prev_region_ && info.size()>1) + continue; + double curr_div = info[kj].min_dist + info[kj].min_ang; + if (curr_div < div) + { + div = curr_div; + ix = (int)kj; + } + } + } + + if (outlier) + { + for (size_t ki=0; ki<group_points_.size(); ++ki) + { + group_points_[ki]->unsetRegion(); + group_points_[ki]->setOutlier(); + group_points_[ki]->addMove(); + } + for (auto it=adjacent_regions_.begin(); it!=adjacent_regions_.end(); ++it) + (*it)->removeAdjacentRegion(this); + //updateInfo(); + return true; + } + else if (ix >= 0) + { + if (info[ix].adjacent->hasSurface()) + { + // Set parameter value, distance and angle difference + shared_ptr<ParamSurface> surf = info[ix].adjacent->getSurface(0)->surface(); + double maxd2, avd2; + int nmb_in2, nmb2_in2; + vector<RevEngPoint*> in2, out2; + vector<pair<double,double> > dist_ang2; + vector<double> parvals2; + RevEngUtils::distToSurf(group_points_.begin(), group_points_.end(), + surf, tol, maxd2, avd2, nmb_in2, nmb2_in2, in2, out2, + parvals2, dist_ang2, angtol); + bool cyllike = (surf->instanceType() == Class_Cylinder || + surf->instanceType() == Class_Cone); + int sf_flag = defineSfFlag(0, tol, nmb_in2, nmb2_in2, avd2, cyllike); + for (size_t ki=0; ki<group_points_.size(); ++ki) + { + group_points_[ki]->setPar(Vector2D(parvals2[2*ki],parvals2[2*ki+1])); + group_points_[ki]->setSurfaceDist(dist_ang2[ki].first, dist_ang2[ki].second); + } + setSurfaceFlag(sf_flag); + } + for (size_t ki=0; ki<group_points_.size(); ++ki) + group_points_[ki]->addMove(); + vector<pair<double, double> > dummy; + info[ix].adjacent->addRegion(this, dummy); + for (auto it=adjacent_regions_.begin(); it!=adjacent_regions_.end(); ++it) + (*it)->removeAdjacentRegion(this); + info[ix].adjacent->updateInfo(tol, angtol); + return true; + } + return false; +} + +//=========================================================================== +bool RevEngRegion::computeIntegrateInfo(vector<RevEngPoint*>& points, RevEngRegion *adj_reg, + double tol, double angtol, double radius, + bool local_approx, int min_next, int max_next, + int max_nmb_outlier, bool& outlier, int& nmb_pt_adj, + double& maxdist, double& avdist, int& nmb_in, + double& maxdist_adj, double& avdist_adj, + int& nmb_in_adj, int& nmb_in_adj2) +//=========================================================================== +{ + outlier = false; + nmb_pt_adj = 0; + + shared_ptr<ParamSurface> surf; + if (adj_reg->hasSurface()) + { + surf = adj_reg->getSurface(0)->surface(); + adj_reg->getAccuracy(maxdist_adj, avdist_adj, nmb_in_adj, nmb_in_adj2); + } + else if (adj_reg->hasBaseSf()) + { + adj_reg->getBase(surf, maxdist_adj, avdist_adj, nmb_in_adj, nmb_in_adj2); + nmb_in_adj2 = nmb_in_adj; + } + + if (surf.get()) + { + // Fetch accuracy of current surface + nmb_pt_adj = adj_reg->numPoints(); + + // Check accuracy of new points + vector<RevEngPoint*> in, out; + vector<pair<double,double> > dist_ang; + vector<double> parvals; + int nmb2_in; + RevEngUtils::distToSurf(points.begin(), points.end(), + surf, tol, maxdist, avdist, nmb_in, nmb2_in, in, out, + parvals, dist_ang, angtol); + } + else if (local_approx) + { + // Fetch nearby points + vector<RevEngPoint*> nearpts; + if (adj_reg->numPoints() < min_next) + nearpts.insert(nearpts.end(), adj_reg->pointsBegin(), adj_reg->pointsEnd()); + else + { + for (size_t ki=0; ki<points.size(); ++ki) + { + nearpts.clear(); + points[ki]->fetchClosePoints2(radius, min_next, + max_next-(int)points.size(), + nearpts, adj_reg); + if ((int)nearpts.size() > max_nmb_outlier) + break; + } + } + size_t nearnmb = nearpts.size(); + nmb_pt_adj = (int)nearnmb; + if (((int)(nearnmb+points.size()) <= max_nmb_outlier) || + ((int)nearnmb <= max_nmb_outlier && adj_reg->numPoints() > min_next)) + { + if ((int)points.size() <= max_nmb_outlier) + outlier = true; + return false; + } + + nearpts.insert(nearpts.end(), points.begin(), points.end()); + BoundingBox bbox = bbox_; + for (size_t ki=0; ki<nearnmb; ++ki) + { + Vector3D xyz = nearpts[ki]->getPoint(); + Point xyz2(xyz[0], xyz[1], xyz[2]); + bbox.addUnionWith(xyz2); + } + surf = surfApprox(nearpts, bbox); + + // Check accuracy + vector<RevEngPoint*> in1, in2, out1, out2; + vector<pair<double,double> > dist_ang1, dist_ang2; + vector<double> parvals1, parvals2; + int nmb2_in, nmb2_in_adj; + RevEngUtils::distToSurf(nearpts.begin(), nearpts.begin()+nearnmb, surf, + tol, maxdist_adj, avdist_adj, nmb_in_adj, + nmb2_in_adj, in1, out1, + parvals1, dist_ang1, angtol); + RevEngUtils::distToSurf(nearpts.begin()+nearnmb, nearpts.end(), surf, + tol, maxdist, avdist, nmb_in, nmb2_in, in2, out2, + parvals2, dist_ang2, angtol); + } + + return true; +} + +//=========================================================================== +bool RevEngRegion::adjustWithCylinder(Point mainaxis[3], + double tol, double angtol, int min_pt_reg, + vector<vector<RevEngPoint*> >& out_groups, + vector<RevEngRegion*>& grown_regions, + vector<HedgeSurface*>& adj_surfs) +//=========================================================================== +{ + if (!hasSurface()) + return false; + + HedgeSurface *hedge = getSurface(0); + int code; + ClassType type = hedge->instanceType(code); + if (type != Class_Cylinder && + (!(type == Class_SplineSurface && code == LINEARSWEPT_SURF))) + return false; + shared_ptr<ParamSurface> surf = hedge->surface(); + +#ifdef DEBUG_ADJUST + std::ofstream of("cylinder_adjust.g2"); + writeRegionInfo(of); +#endif + + // Make bounding parameter domain + int ixd = (type == Class_Cylinder) ? 0 : 2; + //int ixd2 = (ixd == 0) ? 2 : 0; + int ixp = ixd/2; + double dom[4]; + Vector2D uv = group_points_[0]->getPar(); + dom[0] = dom[1] = uv[0]; + dom[2] = dom[3] = uv[1]; + double dist, ang, avang; + double fac = 1.0/(double)group_points_.size(); + group_points_[0]->getSurfaceDist(dist, ang); + avang = fac*ang; + for (size_t ki=1; ki<group_points_.size(); ++ki) + { + Vector2D uv = group_points_[ki]->getPar(); + group_points_[ki]->getSurfaceDist(dist, ang); + dom[0] = std::min(dom[0], uv[0]); + dom[1] = std::max(dom[1], uv[0]); + dom[2] = std::min(dom[2], uv[1]); + dom[3] = std::max(dom[3], uv[1]); + avang += fac*ang; + } + +#ifdef DEBUG_ADJUST + std::ofstream ofp("projected_pts.g2"); +#endif + + Point axis, pnt; + shared_ptr<ParamCurve> crv; + if (type == Class_Cylinder) + { + shared_ptr<Cylinder> cyl = dynamic_pointer_cast<Cylinder,ParamSurface>(surf); + axis = cyl->getAxis(); + pnt = cyl->getLocation(); + shared_ptr<Circle> circ(new Circle(cyl->radius(0,0), pnt, axis, cyl->direction2())); + crv = circ; + } + else + { + vector<Point> der(3); + double upar = 0.5*(dom[0]+dom[1]); + double vpar = 0.5*(dom[2]+dom[3]); + surf->point(der, upar, vpar, 1); + axis = der[1]; + axis.normalize(); + pnt = der[0]; + vector<shared_ptr<ParamCurve> > cvs = surf->constParamCurves(vpar, true); + crv = cvs[0]; + } + + vector<Point> projected; + double maxdp, avdp; + RevEngUtils::projectToPlane(group_points_, axis, pnt, projected, maxdp, avdp); +#ifdef DEBUG_ADJUST + ofp << "400 1 0 4 255 0 0 255" << std::endl; + ofp << projected.size() << std::endl; + for (size_t kr=0; kr<projected.size(); ++kr) + ofp << projected[kr] << std::endl; + crv->writeStandardHeader(ofp); + crv->write(ofp); +#endif + + // Reduce domain from the start + vector<RevEngPoint*> outer; + double del = 0.02; + double del2 = del*(dom[ixd+1] - dom[ixd]); + double par; + int knmb = 10; + int ka; + double dfac = 2.0; + //double afac = 2.0; + double pfac = 0.5; + int part = (int)(del*(double)group_points_.size()); + for (ka=0, par=dom[ixd]+del2; ka<knmb; ++ka, par+=del2) + { + vector<RevEngPoint*> curr_pts; + double avd = 0.0, ava = 0.0; + int nn = 0; + for (size_t ki=0; ki<group_points_.size(); ++ki) + { + Vector2D uv = group_points_[ki]->getPar(); + if (uv[ixp] >= par-del2 && uv[ixp]<par) + { + curr_pts.push_back(group_points_[ki]); + group_points_[ki]->getSurfaceDist(dist, ang); + avd += dist; + ava += ang; + ++nn; + } + } + avd /= (double)nn; + ava /= (double)nn; + + // Check with adjacent regions +#ifdef DEBUG_ADJUST + std::ofstream ofo("outer_cand.g2"); + ofo << "400 1 0 4 0 255 0 255" << std::endl; + ofo << curr_pts.size() << std::endl; + for (size_t ki=0; ki<curr_pts.size(); ++ki) + ofo << curr_pts[ki]->getPoint() << std::endl; +#endif + + vector<RevEngRegion*> next_reg; + vector<int> nmb_next; + for (size_t ki=0; ki<curr_pts.size(); ++ki) + { + vector<RevEngRegion*> adjr; + curr_pts[ki]->adjacentRegions(adjr); + for (size_t kj=0; kj<adjr.size(); ++kj) + { + size_t kr=0; + for (kr=0; kr<next_reg.size(); ++kr) + if (next_reg[kr] == adjr[kj]) + break; + if (kr == next_reg.size()) + { + next_reg.push_back(adjr[kj]); + nmb_next.push_back(1); + } + else + nmb_next[kr]++; + } + } + + + if (avd > dfac*avdist_ && (ava > dfac*avang || nn < pfac*part)) + { + outer.insert(outer.end(), curr_pts.begin(), curr_pts.end()); + dom[ixd] = par; + } + else + break; + int stop_break = 1; + } + + // Reduce domain from the end + for (ka=0, par=dom[ixd+1]-del2; ka<knmb; ++ka, par-=del2) + { + vector<RevEngPoint*> curr_pts; + double avd = 0.0, ava = 0.0; + int nn = 0; + for (size_t ki=0; ki<group_points_.size(); ++ki) + { + Vector2D uv = group_points_[ki]->getPar(); + if (uv[ixp] > par && uv[ixp]<=par+del2) + { + curr_pts.push_back(group_points_[ki]); + group_points_[ki]->getSurfaceDist(dist, ang); + avd += dist; + ava += ang; + ++nn; + } + } + avd /= (double)nn; + ava /= (double)nn; + // Check with adjacent regions +#ifdef DEBUG_ADJUST + std::ofstream ofo("outer_cand.g2"); + ofo << "400 1 0 4 0 255 0 255" << std::endl; + ofo << curr_pts.size() << std::endl; + for (size_t ki=0; ki<curr_pts.size(); ++ki) + ofo << curr_pts[ki]->getPoint() << std::endl; +#endif + + vector<RevEngRegion*> next_reg; + vector<int> nmb_next; + for (size_t ki=0; ki<curr_pts.size(); ++ki) + { + vector<RevEngRegion*> adjr; + curr_pts[ki]->adjacentRegions(adjr); + for (size_t kj=0; kj<adjr.size(); ++kj) + { + size_t kr=0; + for (kr=0; kr<next_reg.size(); ++kr) + if (next_reg[kr] == adjr[kj]) + break; + if (kr == next_reg.size()) + { + next_reg.push_back(adjr[kj]); + nmb_next.push_back(1); + } + else + nmb_next[kr]++; + } + } + + + if (avd > dfac*avdist_ && (ava > dfac*avang || nn < pfac*part)) + { + outer.insert(outer.end(), curr_pts.begin(), curr_pts.end()); + dom[ixd+1] = par; + } + else + break; + int stop_break = 1; + } + + // Integrate points from adjacent regions + vector<vector<RevEngPoint*> > adjpts; + vector<RevEngRegion*> adjreg; + vector<vector<double> > par_and_dist; + for (auto it=adjacent_regions_.begin(); it!=adjacent_regions_.end(); ++it) + { +#ifdef DEBUG_ADJUST + std::ofstream of2("adj_group.g2"); + int num = (*it)->numPoints(); + of2 << "400 1 0 4 255 0 0 255" << std::endl; + of2 << num << std::endl; + for (int ka=0; ka<num; ++ka) + of2 << (*it)->getPoint(ka)->getPoint() << std::endl; +#endif + + vector<Point> projected2; + double maxdp2, avdp2; + vector<RevEngPoint*> curr_pts = (*it)->getPoints(); + RevEngUtils::projectToPlane(curr_pts, axis, pnt, projected2, maxdp2, avdp2); +#ifdef DEBUG_ADJUST + std::ofstream ofp2("projected_pts_adj.g2"); + ofp2 << "400 1 0 4 100 155 0 255" << std::endl; + ofp2 << projected2.size() << std::endl; + for (size_t kr=0; kr<projected2.size(); ++kr) + ofp2 << projected2[kr] << std::endl; +#endif + + if ((*it)->hasSurface()) + { + shared_ptr<ParamSurface> surf2((*it)->getSurface(0)->surface()->clone()); + double upar2, vpar2, dist; + Point close; + surf2->closestPoint(pnt, upar2, vpar2, close, dist, tol); + if (!surf2->isBounded()) + { + BoundingBox bb = getBbox(); + double len = bb.low().dist(bb.high()); + shared_ptr<Cylinder> elem1 = + dynamic_pointer_cast<Cylinder,ParamSurface>(surf2); + shared_ptr<Plane> elem2 = + dynamic_pointer_cast<Plane,ParamSurface>(surf2); + if (elem1.get()) + elem1->setParamBoundsV(-len, len); + else if (elem2.get()) + elem2->setParameterBounds(-len, -len, len, len); + } + +#ifdef DEBUG_ADJUST + if (surf2->isBounded()) + { + vector<shared_ptr<ParamCurve> > cvs2_1 = surf2->constParamCurves(upar2, false); + vector<shared_ptr<ParamCurve> > cvs2_2 = surf2->constParamCurves(vpar2, true); + cvs2_1[0]->writeStandardHeader(ofp2); + cvs2_1[0]->write(ofp2); + cvs2_2[0]->writeStandardHeader(ofp2); + cvs2_2[0]->write(ofp2); + } +#endif + } + + vector<RevEngPoint*> curr_adjpts; + vector<double> curr_par_and_dist; + double avd, ava; + int nn; + getAdjInsideDist(surf, dom, tol, *it, avd, ava, nn, curr_adjpts, curr_par_and_dist); + + if (avd < dfac*avdist_ /*&& (ava < dfac*avang || nn == num)*/) + { + adjpts.push_back(curr_adjpts); + adjreg.push_back(*it); + par_and_dist.push_back(curr_par_and_dist); + } + } + +#ifdef DEBUG_ADJUST + std::ofstream of2("move2pts.g2"); + for (size_t ki=0; ki<adjpts.size(); ++ki) + { + of2 << "400 1 0 4 75 75 75 255" << std::endl; + of2 << adjpts[ki].size() << std::endl; + for (size_t kh=0; kh<adjpts[ki].size(); ++kh) + of2 << adjpts[ki][kh]->getPoint() << std::endl; + } +#endif + + // Adjust point groups + if (outer.size() > 0) + { + extractSpesPoints(outer, out_groups); + splitRegion(out_groups); + } + + for (size_t ki=0; ki<adjpts.size(); ++ki) + { + for (size_t kh=0; kh<adjpts[ki].size(); ++kh) + { + adjpts[ki][kh]->setMoved(); + adjreg[ki]->removePoint(adjpts[ki][kh]); + adjpts[ki][kh]->setRegion(this); + adjpts[ki][kh]->setPar(Vector2D(par_and_dist[ki][4*kh], + par_and_dist[ki][4*kh+1])); + adjpts[ki][kh]->setSurfaceDist(par_and_dist[ki][4*kh+2], par_and_dist[ki][4*kh+3]); + addPoint(adjpts[ki][kh]); + } + + if (adjreg[ki]->numPoints() == 0) + { + for (auto it=adjreg[ki]->adjacent_regions_.begin(); + it!=adjreg[ki]->adjacent_regions_.end(); ++it) + { + if (*it != this) + { + (*it)->addAdjacentRegion(this); + (*it)->removeAdjacentRegion(adjreg[ki]); + } + } + grown_regions.push_back(adjreg[ki]); + int num_sf = adjreg[ki]->numSurface(); + for (int kb=0; kb<num_sf; ++kb) + adj_surfs.push_back(adjreg[ki]->getSurface(kb)); + + removeAdjacentRegion(adjreg[ki]); + } + else + { + if (adjreg[ki]->hasSurface()) + { + if (adjreg[ki]->numPoints() >= min_pt_reg) + adjreg[ki]->checkReplaceSurf(mainaxis, min_pt_reg, + tol, angtol); + else + { + int num_sf = adjreg[ki]->numSurface(); + for (int kb=0; kb<num_sf; ++kb) + adj_surfs.push_back(adjreg[ki]->getSurface(kb)); + adjreg[ki]->clearSurface(); + } + } + else + adjreg[ki]->updateInfo(tol, angtol); + } + } + + //updateInfo(); + checkReplaceSurf(mainaxis, min_pt_reg, tol, angtol); + + + return (outer.size() > 0 || adjpts.size() > 0); +} + +//=========================================================================== +void RevEngRegion::getAdjInsideDist(shared_ptr<ParamSurface> surf, double dom[4], + double tol, RevEngRegion* reg, + double& avd, double& ava, int& nn, + vector<RevEngPoint*>& adjpts, + vector<double>& par_and_dist) +//=========================================================================== +{ + double maxdd, avdd; + int num_inside, num2_inside; + vector<pair<double, double> > dist_ang; + vector<double> parvals; + vector<RevEngPoint*> in, out; + RevEngUtils::distToSurf(reg->pointsBegin(), + reg->pointsEnd(), surf, tol, maxdd, avdd, + num_inside, num2_inside, in, out, parvals, dist_ang); + avd = 0.0; + ava = 0.0; + nn = 0; + for (int kh=0; kh<(int)dist_ang.size(); ++kh) + { + if (parvals[2*kh] >= dom[0] && parvals[2*kh] <= dom[1] && + parvals[2*kh+1] >= dom[2] && parvals[2*kh+1] <= dom[3]) + { + adjpts.push_back(reg->getPoint(kh)); + par_and_dist.push_back(parvals[2*kh]); + par_and_dist.push_back(parvals[2*kh+1]); + par_and_dist.push_back(dist_ang[kh].first); + par_and_dist.push_back(dist_ang[kh].second); + avd += dist_ang[kh].first; + ava += dist_ang[kh].second; + ++nn; + } + } + if (nn > 0) + { + avd /= (double)nn; + ava /= (double)nn; + } +} + +//=========================================================================== +void RevEngRegion::addRegion(RevEngRegion* reg, + vector<pair<double, double> >& dist_ang, + double maxd, double avd, int num_inside, + int num_inside2) +//=========================================================================== +{ + int num = reg->numPoints(); +#ifdef DEBUG_CHECK + for (int ki=0; ki<num; ++ki) + { + auto it = std::find(group_points_.begin(), group_points_.end(), reg->getPoint(ki)); + if (it != group_points_.end()) + std::cout << "addRegion: point exists already. " << it-group_points_.begin() <<" " << reg << " ki= " << ki << " point: " << reg->getPoint(ki) << std::endl; + } +#endif + + bbox_.addUnionWith(reg->boundingBox()); + normalcone_.addUnionWith(reg->getNormalCone()); + normalcone2_.addUnionWith(reg->getNormalConeTriang()); + if (num_inside >= 0) + { + maxdist_ = std::max(maxdist_, maxd); + double div = (double)((int)group_points_.size() + num); + avdist_ = ((double)(group_points_.size())*avdist_ + num*avd)/div; + num_inside_ += num_inside; + num_inside2_ += num_inside2; + } + + double mink1, maxk1, mink2, maxk2; + reg->getPrincipalCurvatureInfo(mink1, maxk1, mink2, maxk2); + mink1_ = std::min(mink1_, mink1); + maxk1_ = std::max(maxk1_, maxk1); + mink2_ = std::min(mink2_, mink2); + maxk2_ = std::max(maxk2_, maxk2); + + int num_all = numPoints() + reg->numPoints(); + double fac1 = (double)numPoints()/(double)num_all; + double fac2 = (double)reg->numPoints()/(double)num_all; + double avH, avK, MAH, MAK; + reg->getAvCurvatureInfo(avH, avK, MAH, MAK); + Point avnorm = reg->getMeanNormal(); + Point avnorm2 = reg->getMeanNormalTriang(); + avH_ = fac1*avH_ + fac2*avH; + avK_ = fac1*avK_ + fac2*avK; + MAH_ = fac1*MAH_ + fac2*MAH; + MAK_ = fac1*MAK_ + fac2*MAK; + avnorm_ = fac1*avnorm_ + fac2*avnorm; + avnorm2_ = fac1*avnorm2_ + fac2*avnorm2; + + size_t kr=0; + for (auto it=reg->pointsBegin(); it != reg->pointsEnd(); ++it, ++kr) + { + if (dist_ang.size() > 0) + (*it)->setSurfaceDist(dist_ang[kr].first, dist_ang[kr].second); + (*it)->setRegion(this); + } + group_points_.insert(group_points_.end(), reg->pointsBegin(), + reg->pointsEnd()); + removeAdjacentRegion(reg); + + if (hasSurface()) + computeDomain(); + +} + + +//=========================================================================== +bool RevEngRegion::includeAdjacent(RevEngRegion* adj, Point mainaxis[3], + double tol, double angtol, + vector<RevEngRegion*>& grown_regions, + vector<HedgeSurface*>& adj_surfs) +//=========================================================================== +{ + if (!hasSurface()) + return false; + + // Check accuracy + shared_ptr<ParamSurface> surf = getSurface(0)->surface(); + double maxdist, avdist; + int num_in, num2_in; + vector<RevEngPoint*> inpt, outpt; + vector<pair<double, double> > dist_ang; + vector<double> parvals; + RevEngUtils::distToSurf(adj->pointsBegin(), adj->pointsEnd(), surf, + tol, maxdist, avdist, num_in, num2_in, inpt, outpt, + parvals, dist_ang, angtol); + + bool type_cyl = (surf->instanceType() == Class_Cylinder || + surf->instanceType() == Class_Cone); + int num_pt_adj = adj->numPoints(); + int sf_flag = defineSfFlag(num_pt_adj, 0, tol, num_in, num2_in, + avdist, type_cyl); + int adj_flag = adj->getSurfaceFlag(); + if (sf_flag < NOT_SET && + (sf_flag <= adj_flag || + (sf_flag == PROBABLE_HELIX && adj_flag == ANGULAR_DEVIATION) || + (num_in > num_pt_adj/2 && avdist <= tol))) + { + // Include + vector<RevEngRegion*> added_adjacent; + includeAdjacentRegion(adj, maxdist, avdist, num_in, num2_in, + parvals, dist_ang, added_adjacent); + grown_regions.push_back(adj); + int num_sf = adj->numSurface(); + for (int kb=0; kb<num_sf; ++kb) + adj_surfs.push_back(adj->getSurface(kb)); + removeAdjacentRegion(adj); + setSurfaceFlag(sf_flag); + + checkReplaceSurf(mainaxis, 0, tol, angtol); + return true; + } + return false; +} + +//=========================================================================== +void RevEngRegion::growWithSurf(Point mainaxis[3], int min_pt_reg, double tol, + double angtol, vector<RevEngRegion*>& grown_regions, + vector<HedgeSurface*>& adj_surfs, + vector<RevEngEdge*>& adj_edgs, bool use_base) +//=========================================================================== +{ + //double eps = 1.0e-6; + if (associated_sf_.size() == 0) + return; // No surface to grow + + if (hasAssociatedBlend()) + return; + + size_t num_group_points = group_points_.size(); + + shared_ptr<ParamSurface> surf = associated_sf_[0]->surface(); + int classtype = surf->instanceType(); + bool cyllike = (classtype == Class_Cylinder || classtype == Class_Cone); + + vector<RevEngRegion*> adj_reg; + adj_reg.insert(adj_reg.end(), adjacent_regions_.begin(), adjacent_regions_.end()); + for (size_t ki=0; ki<adj_reg.size(); ++ki) + for (size_t kj=ki+1; kj<adj_reg.size(); ++kj) + if (adj_reg[kj]->numPoints() > adj_reg[ki]->numPoints()) + std::swap(adj_reg[ki], adj_reg[kj]); + + vector<grow_cand> cands; + bool changed = false; + for (size_t ki=0; ki<adj_reg.size(); ++ki) + { + if ((adj_reg[ki]->prev_region_ && adj_reg[ki]->prev_region_ == this) || + adj_reg[ki]->hasAssociatedBlend()) + { + continue; + } + + int num = adj_reg[ki]->numPoints(); + +#ifdef DEBUG_GROW + int write_extend = 1; + std::ofstream of("curr_extend.g2"); + if (write_extend) + { + of << "400 1 0 4 0 255 0 255" << std::endl; + of << group_points_.size() << std::endl; + for (size_t kh=0; kh<group_points_.size(); ++kh) + of << group_points_[kh]->getPoint() << std::endl; + + of << "400 1 0 4 255 0 0 255" << std::endl; + of << num << std::endl; + for (int ka=0; ka<num; ++ka) + of << adj_reg[ki]->getPoint(ka)->getPoint() << std::endl; + surf->writeStandardHeader(of); + surf->write(of); + } +#endif + + double maxd, avd; + int num_in, num2_in; + vector<RevEngPoint*> in, out; + vector<pair<double, double> > dist_ang; + vector<double> parvals; + RevEngUtils::distToSurf(adj_reg[ki]->pointsBegin(), + adj_reg[ki]->pointsEnd(), surf, tol, + maxd, avd, num_in, num2_in, + in, out, parvals, dist_ang, angtol); + int num_ang_in = 0; + double avang = 0.0; + double nfac = 1.0/(double)num; + for (size_t kh=0; kh<dist_ang.size(); ++kh) + { + avang += nfac*dist_ang[kh].second; + if (dist_ang[kh].second <= angtol) + num_ang_in++; + } + + int adj_sf_flag = adj_reg[ki]->defineSfFlag(0, tol, num_in, num2_in, + avd, cyllike); + + double tol_fac = 2.0; + double tol_fac2 = 5.0; + double ang_lim = 0.9; + double num2_lim = 0.25; + if (adj_sf_flag == ACCURACY_OK || + (adj_sf_flag <= surfflag_ && + avd <= tol_fac*tol && (double)num_ang_in >= ang_lim*(double)num && + (double)num2_in >= num2_lim*(double)num2_in)) + { + // Accepted. Should possibly have a test on number of points and number + // of neighbours + changed = true; + + // Include adjacent region in present + vector<RevEngRegion*> added_adjacent; + includeAdjacentRegion(adj_reg[ki], maxd, avd, num_in, + num2_in, parvals, dist_ang, + added_adjacent); + grown_regions.push_back(adj_reg[ki]); + + int num_sf = adj_reg[ki]->numSurface(); + for (int kb=0; kb<num_sf; ++kb) + adj_surfs.push_back(adj_reg[ki]->getSurface(kb)); + if (adj_reg[ki]->numRevEdges() > 0) + { + vector<RevEngEdge*> rev_edgs = adj_reg[ki]->getAllRevEdges(); + for (size_t kr=0; kr<rev_edgs.size(); ++kr) + { + RevEngRegion *adj1, *adj2; + rev_edgs[kr]->getAdjacent(adj1, adj2); + RevEngRegion *other = (adj1 == adj_reg[ki]) ? adj2 : adj1; + other->removeRevEngEdge(rev_edgs[kr]); + } + adj_edgs.insert(adj_edgs.end(), rev_edgs.begin(), rev_edgs.end()); + } + } + else if (avd <= tol_fac2*tol && (double)num_ang_in >= ang_lim*(double)num) + { + grow_cand curr_cand(adj_reg[ki], maxd, avd, avang, num_in, num2_in, + num_ang_in); + cands.push_back(curr_cand); + } + } + + // Check if the surface should be updated + if (changed) + checkReplaceSurf(mainaxis, min_pt_reg, tol, angtol); + + // Integrate candidate neighbours if feasible + if (cands.size() > 0) + { + integrateGrowCand(cands, mainaxis, tol, angtol, grown_regions, + adj_surfs); + int stop_break = 1; + } + + double fac = 1.5; + if ((int)group_points_.size() > (int)(fac*(double)num_group_points) || + adj_surfs.size() > 0) + { + for (size_t kj=0; kj<rev_edges_.size(); ++kj) + rev_edges_[kj]->increaseExtendCount(); + } +} + + +//=========================================================================== +int RevEngRegion::getGrowAccuracy(RevEngRegion *other, double tol, + double angtol, double& maxdist, + double& avdist, int& num_inside, + int& num2_inside, double& maxdist2, + double& avdist2, int& num_in2, + int& num2_in2,vector<double>& parvals, + vector<pair<double,double> >& distang) +//=========================================================================== +{ + if (!hasSurface()) + return NOT_SET; + + shared_ptr<ParamSurface> surf = getSurface(0)->surface(); + + vector<RevEngPoint*> in, out; + RevEngUtils::distToSurf(other->pointsBegin(), + other->pointsEnd(), surf, tol, + maxdist2, avdist2, num_in2, num2_in2, + in, out, parvals, distang, angtol); + + maxdist = std::max(maxdist_, maxdist2); + int all_pts = (int)group_points_.size() + other->numPoints(); + double fac1 = (double)(group_points_.size())/(double)all_pts; + double fac2 = (double)(other->numPoints())/(double)all_pts; + avdist = fac1*avdist_ + fac2*avdist2; + num_inside = num_inside_ + num_in2; + num2_inside = num_inside2_ + num2_in2; + + bool cyllike = (surf->instanceType() == Class_Cylinder || + surf->instanceType() == Class_Cone); + int sf_flag = other->defineSfFlag(0, tol, num_in2, num2_in2, avdist2, + cyllike); + return sf_flag; + } + +//=========================================================================== +void RevEngRegion::getDomainBoundaries(double tol, double angtol, + vector<pair<int, double> >& bd_par1, + vector<pair<int, double> >& bd_par2) +//=========================================================================== +{ + if (!hasSurface()) + return; + + // Check domain + double angtol2 = 1.1*angtol; + double dom[4]; + int ka; + int num_pt = (int)group_points_.size(); + double dist, ang; + for (ka=0; ka<num_pt; ++ka) + { + Vector2D uv = group_points_[ka]->getPar(); + group_points_[ka]->getSurfaceDist(dist, ang); + if (ang <= angtol2) + { + dom[0] = dom[1] = uv[0]; + dom[2] = dom[3] = uv[1]; + break; + } + } + for (; ka<num_pt; ++ka) + { + Vector2D uv = group_points_[ka]->getPar(); + group_points_[ka]->getSurfaceDist(dist, ang); + if (ang > angtol2) + continue; + dom[0] = std::min(dom[0], uv[0]); + dom[1] = std::max(dom[1], uv[0]); + dom[2] = std::min(dom[2], uv[1]); + dom[3] = std::max(dom[3], uv[1]); + } + + + // boundary index: 0=umin, 1=umax, 2=vmin, 3=vmax + for (size_t ki=0; ki<trim_edgs_.size(); ++ki) + { + shared_ptr<CurveOnSurface> sfcv = + dynamic_pointer_cast<CurveOnSurface,ParamCurve>(trim_edgs_[ki]->geomCurve()); + int dir; + double parval; + if (sfcv->isConstantCurve(tol, dir, parval)) + { + bool same; + int bd = sfcv->whichBoundary(tol, same); + if (bd >= 0) + bd_par1.push_back(std::make_pair(bd, parval)); + } + } + + for (size_t ki=0; ki<bd_par1.size(); ki++) + for (size_t kj=1; kj<bd_par1.size(); ++kj) + if (bd_par1[kj].first < bd_par1[ki].first) + std::swap(bd_par1[ki], bd_par1[kj]); + + int ix=0; + size_t kj; + for (size_t ki=0; ki<bd_par1.size(); ki=kj) + { + for (kj=ki+1; kj<bd_par1.size(); ++kj) + if (bd_par1[ki].first != bd_par1[kj].first) + break; + if (kj > ki+1) + { + // Check consistence + double tmin, tmax; + tmin = tmax = bd_par1[ki].second; + for (size_t kr=ki+1; kr<kj; ++kr) + { + tmin = std::min(tmin, bd_par1[kr].second); + tmax = std::min(tmax, bd_par1[kr].second); + } + if (tmax - tmin > tol) + { + bd_par1.erase(bd_par1.begin()+ki, bd_par1.begin()+kj); + kj = ki; + } + else + { + bd_par1[ki] = std::make_pair(bd_par1[ki].first, 0.5*(tmin+tmax)); + bd_par1.erase(bd_par1.begin()+ki+1, bd_par1.begin()+kj); + kj = ki+1; + } + } + if (bd_par1[ki].first != ix) + bd_par2.push_back(std::make_pair(ix, dom[ix])); + ++ix; + } + + for (; ix<4; ++ix) + bd_par2.push_back(std::make_pair(ix, dom[ix])); + +} + +//=========================================================================== +void RevEngRegion::growBlendSurf(vector<RevEngRegion*>& next_blend, double tol, + double angtol, vector<RevEngRegion*>& grown_regions, + vector<vector<RevEngPoint*> >& added_regions) +//=========================================================================== +{ + if (!hasSurface()) + return; + + if (!hasBlendEdge()) + return; + RevEngRegion *adj1, *adj2; + blend_edge_->getAdjacent(adj1, adj2); + + // Set absolute and vague domain boundaries + vector<pair<int, double> > bd_par1; + vector<pair<int, double> > bd_par2; + getDomainBoundaries(tol, angtol, bd_par1, bd_par2); + if (bd_par1.size() == 0) + return; // Not as expected + + vector<RevEngRegion*> adj_reg; + adj_reg.insert(adj_reg.end(), adjacent_regions_.begin(), adjacent_regions_.end()); + for (size_t ki=0; ki<adj_reg.size(); ++ki) + { + if (adj_reg[ki]->hasSurface()) + continue; +#ifdef DEBUG_BLEND + std::ofstream of("curr_blend_adj.g2"); + adj_reg[ki]->writeRegionPoints(of); +#endif + // Compute distance to current surface + shared_ptr<ParamSurface> surf = getSurface(0)->surface(); + double maxd, avd; + int num_in, num2_in; + vector<RevEngPoint*> in, out; + vector<pair<double, double> > dist_ang; + vector<double> parvals; + RevEngUtils::distToSurf(adj_reg[ki]->pointsBegin(), + adj_reg[ki]->pointsEnd(), surf, tol, + maxd, avd, num_in, num2_in, + in, out, parvals, dist_ang, angtol); + + vector<RevEngRegion*> other_adj; + adj_reg[ki]->getAdjacentRegions(other_adj); + if (other_adj.size() == 1 && other_adj[0] == this) + { + // Include adjacent region in current + vector<RevEngRegion*> added_adjacent; + includeAdjacentRegion(adj_reg[ki], maxd, avd, num_in, + num2_in, parvals, dist_ang, + added_adjacent); + adj_reg[ki]->removeFromAdjacent(); + adj_reg[ki]->clearRegionAdjacency(); + grown_regions.push_back(adj_reg[ki]); + + } + else + { + // Distribute points according to identified boundaries + vector<vector<int> > out1_ix(bd_par1.size()); + vector<int> in1_ix; + double eps = 1.0e-9; + int num = adj_reg[ki]->numPoints(); + vector<RevEngPoint*> adj_pts = adj_reg[ki]->getPoints(); + for (int ka=0; ka<num; ++ka) + { + size_t kj=0; + for (kj=0; kj<bd_par1.size(); ++kj) + { + int ix = (bd_par1[kj].first <= 1) ? 0 : 1; + int sgn = (bd_par1[kj].first%2 == 0) ? -1 : 1; + if ((sgn < 0 && parvals[2*ka+ix] < bd_par1[kj].second+eps) || + (sgn > 0 && parvals[2*ka+ix] > bd_par1[kj].second-eps)) + { + out1_ix[kj].push_back(ka); + break; + } + } + if (kj == bd_par1.size()) + in1_ix.push_back(ka); + } + + if (other_adj.size() == 2) + { + RevEngRegion* other_reg = (other_adj[0] == this) ? + other_adj[1] : other_adj[0]; + if (other_reg == adj1 || other_reg == adj2) + { + if ((int)in1_ix.size() == num) + { + vector<RevEngRegion*> added_adjacent; + includeAdjacentRegion(adj_reg[ki], maxd, avd, num_in, + num2_in, parvals, dist_ang, + added_adjacent); + } + else + { + for (size_t kj=0; kj<in1_ix.size(); ++kj) + { + RevEngPoint *curr = adj_pts[in1_ix[kj]]; + int ix = in1_ix[kj]; + curr->setPar(Vector2D(parvals[2*ix], + parvals[2*ix+1])); + curr->setSurfaceDist(dist_ang[ix].first, dist_ang[ix].second); + adj_reg[ki]->removePoint(curr); + addPoint(curr); + } + shared_ptr<ParamSurface> surf2 = other_reg->getSurface(0)->surface(); + double maxd2, avd2; + int num_in2, num2_in2; + vector<RevEngPoint*> in2, out2; + vector<pair<double, double> > dist_ang2; + vector<double> parvals2; + RevEngUtils::distToSurf(adj_reg[ki]->pointsBegin(), + adj_reg[ki]->pointsEnd(), surf2, + tol, maxd2, avd2, num_in2, + num2_in2, in2, out2, parvals2, + dist_ang2, angtol); + + vector<RevEngRegion*> added_adjacent; + other_reg->includeAdjacentRegion(adj_reg[ki], maxd2, avd2, + num_in2, num2_in2, + parvals2, dist_ang2, + added_adjacent); + + } + adj_reg[ki]->removeFromAdjacent(); + adj_reg[ki]->clearRegionAdjacency(); + grown_regions.push_back(adj_reg[ki]); + continue; + } + } + + if (in1_ix.size() == 0) + continue; + + vector<vector<int> > out2_ix; + vector<int> in2_ix; + if (bd_par2.size() > 0) + { + out2_ix.resize(bd_par2.size()); + for (size_t kr=0; kr<in1_ix.size(); ++kr) + { + int ka = in1_ix[kr]; + size_t kj=0; + for (kj=0; kj<bd_par2.size(); ++kj) + { + int ix = (bd_par2[kj].first <= 1) ? 0 : 1; + int sgn = (bd_par2[kj].first%2 == 0) ? -1 : 1; + if ((sgn < 0 && parvals[2*ka+ix] < bd_par2[kj].second+eps) || + (sgn > 0 && parvals[2*ka+ix] > bd_par2[kj].second-eps)) + { + out2_ix[kj].push_back(ka); + break; + } + } + if (kj == bd_par2.size()) + in2_ix.push_back(ka); + } + } + else + in2_ix = in1_ix; + + // Identify grow candidates from adjacent + vector<RevEngRegion*> adj_grow; + vector<RevEngRegion*> remain_adj; + if (in2_ix.size() < in1_ix.size()) + adj_grow.push_back(this); + for (size_t kj=0; kj<other_adj.size(); ++kj) + { + if (other_adj[kj] == adj1 || other_adj[kj] == adj2) + adj_grow.push_back(other_adj[kj]); + else + { + size_t kh; + for (kh=0; kh<next_blend.size(); ++kh) + if (next_blend[kh] == other_adj[kj]) + break; + if (kh < next_blend.size()) + adj_grow.push_back(other_adj[kj]); + else if (other_adj[kj] != this) + remain_adj.push_back(other_adj[kj]); + } + } + int glast = (int)adj_grow.size()-1; + for (size_t kj=0; kj<adj_grow.size(); ++kj) + if (adj_grow[kj] == adj1) + { + if ((int)kj < glast) + std::swap(adj_grow[kj], adj_grow[glast]); + glast--; + } + for (size_t kj=0; kj<adj_grow.size(); ++kj) + if ((int)kj < glast && adj_grow[kj] == adj2) + std::swap(adj_grow[kj], adj_grow[glast]); + + vector<vector<RevEngPoint*> > in_pts(adj_grow.size()); + for (size_t kj=0; kj<adj_grow.size(); ++kj) + { + for (size_t kh=0; kh<out2_ix.size(); ++kh) + if (out2_ix[kh].size() > 0) + adj_grow[kj]->blendGrowFromAdjacent(adj_reg[ki], out2_ix[kh], + tol, angtol, in_pts[kj]); + if (adj_grow[kj] != this) + { + for (size_t kh=0; kh<out1_ix.size(); ++kh) + if (out1_ix[kh].size() > 0) + adj_grow[kj]->blendGrowFromAdjacent(adj_reg[ki], out1_ix[kh], + tol, angtol, in_pts[kj]); + } + } + + for (int ka=0; ka<num; ++ka) + { + adj_reg[ki]->getPoint(ka)->unsetVisited(); + } + + for (size_t kh=0; kh<in2_ix.size(); ++kh) + { + int ix = in2_ix[kh]; + adj_pts[ix]->setPar(Vector2D(parvals[2*ix], parvals[2*ix+1])); + adj_pts[ix]->setSurfaceDist(dist_ang[ix].first, dist_ang[ix].second); + adj_reg[ki]->removePoint(adj_pts[ix]); + addPoint(adj_pts[ix]); + } + + for (size_t kj=0; kj<adj_grow.size(); ++kj) + { + if (in_pts[kj].size() > 0) + { + shared_ptr<ParamSurface> surf2 = adj_grow[kj]->getSurface(0)->surface(); + double maxd2, avd2; + int num_in2, num2_in2; + vector<RevEngPoint*> in2, out2; + vector<pair<double, double> > dist_ang2; + vector<double> parvals2; + RevEngUtils::distToSurf(in_pts[kj].begin(), in_pts[kj].end(), + surf2, tol, maxd2, avd2, num_in2, + num2_in2, in2, out2, parvals2, + dist_ang2, angtol); + for (size_t kh=0; kh<in_pts[kj].size(); ++kh) + { + in_pts[kj][kh]->setPar(Vector2D(parvals[2*kh], + parvals[2*kh+1])); + in_pts[kj][kh]->setSurfaceDist(dist_ang[kh].first, dist_ang[kh].second); + adj_reg[ki]->removePoint(in_pts[kj][kh]); + adj_grow[kj]->addPoint(in_pts[kj][kh]); + } + + } + adj_grow[kj]->computeDomain(); + } + + if (adj_reg[ki]->numPoints() == 0) + { + adj_reg[ki]->removeFromAdjacent(); + adj_reg[ki]->clearRegionAdjacency(); + grown_regions.push_back(adj_reg[ki]); + } + else + { + vector<vector<RevEngPoint*> > sep_groups; + adj_reg[ki]->splitRegion(sep_groups); + if (sep_groups.size() > 0) + { + added_regions.insert(added_regions.end(), sep_groups.begin(), + sep_groups.end()); + adj_reg[ki]->updateRegionAdjacency(); + } + } + + if (remain_adj.size() > 0) + { + for (size_t kj=0; kj<remain_adj.size(); ++kj) + { + size_t kh; + for (kh=0; kh<adj_reg.size(); ++kh) + if (adj_reg[kh] == remain_adj[kj]) + break; + if (kh == adj_reg.size()) + adj_reg.push_back(remain_adj[kj]); + } +#ifdef DEBUG_BLEND + std::ofstream of2("updated_blend_grow.g2"); + adj_reg[ki]->writeRegionPoints(of2); + for (size_t kr=0; kr<adj_grow.size(); ++kr) + adj_grow[kr]->writeRegionPoints(of2); +#endif + } + int stop_break = 1; + } + } +#ifdef DEBUG_BLEND + std::ofstream of3("updated_blend_grow2.g2"); + writeRegionPoints(of3); + for (size_t ki=0; ki<adj_reg.size(); ++ki) + adj_reg[ki]->writeRegionPoints(of3); +#endif + int stop_break2 = 1; +} + + +//=========================================================================== +void RevEngRegion::blendGrowFromAdjacent(RevEngRegion* adjacent, + vector<int>& pt_ix, double tol, + double angtol, + vector<RevEngPoint*>& grow_pt) +//=========================================================================== +{ + if (!hasSurface()) + return; + + vector<pair<int, double> > bd_par1; + vector<pair<int, double> > bd_par2; + if (hasBlendEdge()) + getDomainBoundaries(tol, angtol, bd_par1, bd_par2); + + double eps = 1.0e-6; + shared_ptr<ParamSurface> surf = getSurface(0)->surface(); + vector<RevEngPoint*> adj_pts = adjacent->getPoints(); + double fac = 1.1; + double tol2 = std::min(fac*tol, avdist_); //fac*std::max(tol, avdist_); + vector<RevEngPoint*> next_pts; + double par[2]; + double dist; + Point close; + Point norm, norm2, norm3; + vector<int> remove_ix; + for (int ka=(int)pt_ix.size()-1; ka>=0; --ka) + { + RevEngPoint* curr = adj_pts[pt_ix[ka]]; + curr->setMarkIx(ka); + if (curr->isNeighbour(this)) + { + curr->setVisited(); + Vector3D xyz = curr->getPoint(); + Point pnt(xyz[0], xyz[1], xyz[2]); + surf->closestPoint(pnt, par[0], par[1], close, dist, eps); + + size_t kh=0; + for (kh=0; kh<bd_par1.size(); ++kh) + { + int ix = (bd_par1[kh].first <= 1) ? 0 : 1; + int sgn = (bd_par1[kh].first%2 == 0) ? -1 : 1; + if ((sgn < 0 && par[ix] < bd_par1[kh].second+eps) || + (sgn > 0 && par[ix] > bd_par1[kh].second-eps)) + break; + } + + size_t kr=0; + for (kr=0; kr<bd_par2.size(); ++kr) + { + int ix = (bd_par2[kr].first <= 1) ? 0 : 1; + int sgn = (bd_par2[kr].first%2 == 0) ? -1 : 1; + if ((sgn < 0 && par[ix] < bd_par2[kr].second+eps) || + (sgn > 0 && par[ix] > bd_par2[kr].second-eps)) + break; + } + + + if (kh == bd_par1.size() && + (dist <= tol2 || (bd_par2.size() > 0 && kr == bd_par2.size()))) + { + surf->normal(norm, par[0], par[1]); + norm2 = curr->getLocFuncNormal(); + norm3 = curr->getTriangNormal(); + double ang = norm.angle(norm2); + double ang2 = norm.angle(norm3); + ang = std::min(std::min(ang,M_PI-ang), std::min(ang2,M_PI-ang2)); + if (dist <= tol || ang < fac*angtol || + (bd_par2.size() > 0 && kr == bd_par2.size() && ang <= angtol)) + { + next_pts.push_back(curr); + grow_pt.push_back(curr); + remove_ix.push_back(ka); + } + } + + } + } + + if (next_pts.size() == 0) + { + for (int ka=(int)pt_ix.size()-1; ka>=0; --ka) + { + RevEngPoint* curr = adj_pts[pt_ix[ka]]; + curr->unsetMarkIx(); + } + return; + } + +#ifdef DEBUG_GROW + std::ofstream of3("seed_blendgrow.g2"); + if (next_pts.size() > 0) + { + of3 << "400 1 0 4 255 0 0 255" << std::endl; + of3 << next_pts.size() << std::endl; + for (size_t kr=0; kr<next_pts.size(); ++kr) + of3 << next_pts[kr]->getPoint() << std::endl; + } + std::ofstream of4("cand_blendgrow.g2"); + if (pt_ix.size() > 0) + { + of4 << "400 1 0 4 0 255 0 255" << std::endl; + of4 << pt_ix.size() << std::endl; + for (size_t kr=0; kr<pt_ix.size(); ++kr) + of4 << adj_pts[pt_ix[kr]]->getPoint() << std::endl; + } +#endif + + // Grow + for (size_t ki=0; ki<next_pts.size(); ++ki) + { + vector<ftSamplePoint*> next2 = next_pts[ki]->getNeighbours(); + for (size_t kj=0; kj<next2.size(); ++kj) + { + RevEngPoint *curr = dynamic_cast<RevEngPoint*>(next2[kj]); + if (curr->visited()) + continue; + RevEngRegion *adj_reg = curr->region(); + if (adj_reg != adjacent) + continue; + if (curr->getMarkIx() < 0) + continue; + curr->setVisited(); + Vector3D xyz = curr->getPoint(); + surf->closestPoint(Point(xyz[0],xyz[1],xyz[2]), par[0], par[1], close, dist, eps); + size_t kh=0; + for (kh=0; kh<bd_par1.size(); ++kh) + { + int ix = (bd_par1[kh].first <= 1) ? 0 : 1; + int sgn = (bd_par1[kh].first%2 == 0) ? -1 : 1; + if ((sgn < 0 && par[ix] < bd_par1[kh].second+eps) || + (sgn > 0 && par[ix] > bd_par1[kh].second-eps)) + break; + } + + size_t kr=0; + for (kr=0; kr<bd_par2.size(); ++kr) + { + int ix = (bd_par2[kr].first <= 1) ? 0 : 1; + int sgn = (bd_par2[kr].first%2 == 0) ? -1 : 1; + if ((sgn < 0 && par[ix] < bd_par2[kr].second+eps) || + (sgn > 0 && par[ix] > bd_par2[kr].second-eps)) + break; + } + + if (kh == bd_par1.size() && + (dist <= tol2 || (bd_par2.size() > 0 && kr == bd_par2.size()))) + { + surf->normal(norm, par[0], par[1]); + norm2 = curr->getLocFuncNormal(); + norm3 = curr->getTriangNormal(); + double ang = norm.angle(norm2); + double ang2 = norm.angle(norm3); + ang = std::min(std::min(ang,M_PI-ang), std::min(ang2,M_PI-ang2)); + if (dist <= tol || ang < fac*angtol || + (bd_par2.size() > 0 && kr == bd_par2.size() && ang <= angtol)) + { + grow_pt.push_back(curr); + next_pts.push_back(curr); + remove_ix.push_back(curr->getMarkIx()); + } + } + } + } + + for (int ka=(int)pt_ix.size()-1; ka>=0; --ka) + { + RevEngPoint* curr = adj_pts[pt_ix[ka]]; + curr->unsetMarkIx(); + } + + if (remove_ix.size() > 1) + std::sort(remove_ix.begin(), remove_ix.end()); + for (int ka=(int)remove_ix.size()-1; ka>=0; --ka) + pt_ix.erase(pt_ix.begin()+remove_ix[ka]); + // for (size_t kj=0; kj<remove_ix.size(); ++kj) + // { + // auto it = std::find(pt_ix.begin(), pt_ix.end(), remove_ix[kj]); + // if (it != pt_ix.end()) + // { + // std::swap(*it, pt_ix[pt_ix.size()-1]); + // pt_ix.pop_back(); + // } + // } +} + + +//=========================================================================== +void RevEngRegion::integrateGrowCand(vector<grow_cand>& cand, + Point mainaxis[3], double tol, + double angtol, vector<RevEngRegion*>& grown_regions, + vector<HedgeSurface*>& adj_surfs) +//=========================================================================== +{ + shared_ptr<ParamSurface> surf = associated_sf_[0]->surface(); + ClassType classtype = surf->instanceType(); + bool cyllike; + double tol3 = 3.0*tol; + double anglim = 0.75; + +#ifdef DEBUG_GROW + std::ofstream of1("source_reg.g2"); + writeRegionPoints(of1); +#endif + // Collect all points + // Better to keep them separate, but don't change all that code now + vector<RevEngPoint*> all_points; + all_points.insert(all_points.end(), group_points_.begin(), group_points_.end()); + while (cand.size() > 0) + { + vector<int> all_num(cand.size()+1); + int num; + all_num[0] = num = (int)group_points_.size(); + for (size_t ki=0; ki<cand.size(); ++ki) + { + all_points.insert(all_points.end(), cand[ki].cand_->pointsBegin(), + cand[ki].cand_->pointsEnd()); + all_num[ki+1] = cand[ki].cand_->numPoints(); + num += all_num[ki+1]; + } + + // Compute updated surface + shared_ptr<ParamSurface> merged1, merged2; + computeSurface(all_points, mainaxis, tol, angtol, classtype, + merged1, merged2, cyllike); + + // Check accuracy + vector<double> maxd(cand.size()+1), avd(cand.size()+1), avang(cand.size()+1, 0.0); + vector<int> num_in(cand.size()+1), num2_in(cand.size()+1), ang_in(cand.size()+1, 0); + vector<vector<double> > parvals(cand.size()+1); + vector<vector<pair<double,double> > > dist_ang(cand.size()+1); + vector<RevEngPoint*> inpt, outpt; + + if (!merged1.get()) + { + cand.clear(); + break; + } + RevEngUtils::distToSurf(group_points_.begin(), group_points_.end(), merged1, + tol, maxd[0], avd[0], num_in[0], num2_in[0], inpt, + outpt, parvals[0], dist_ang[0], angtol); + if (merged2.get()) + { + double maxd2, avd2; + int num_in2, num2_in2; + vector<double> parvals2; + vector<pair<double,double> > dist_ang2; + vector<RevEngPoint*> inpt2, outpt2; + RevEngUtils::distToSurf(group_points_.begin(), group_points_.end(), merged2, + tol, maxd2, avd2, num_in2, num2_in2, inpt, + outpt2, parvals2, dist_ang2, angtol); + if (avd2 < avd[0] && num_in2+num2_in2 > num_in[0]+num2_in[0]) + { + std::swap(merged1, merged2); + std::swap(maxd[0], maxd2); + std::swap(avd[0], avd2); + std::swap(num_in[0], num_in2); + std::swap(num2_in[0], num2_in2); + std::swap(parvals[0], parvals2); + std::swap(dist_ang[0], dist_ang2); + } + } + double frac = 1.0/(double)group_points_.size(); + for (size_t kh=0; kh<dist_ang[0].size(); ++kh) + { + avang[0] += frac*dist_ang[0][kh].second; + if (dist_ang[0][kh].second <= angtol) + ang_in[0]++; + } + + double maxdist = maxd[0]; + double avdist = (double)all_num[0]*avd[0]/(double)num; + int num_inside = num_in[0]; + int num2_inside = num2_in[0]; + double meanang = (double)all_num[0]*avang[0]/(double)num; + int inside_ang = ang_in[0]; + + for (size_t ki=0; ki<cand.size(); ++ki) + { + inpt.clear(); + outpt.clear(); + RevEngUtils::distToSurf(cand[ki].cand_->pointsBegin(), + cand[ki].cand_->pointsEnd(), merged1, + tol, maxd[ki+1], avd[ki+1], num_in[ki+1], num2_in[ki+1], + inpt, outpt, parvals[ki+1], dist_ang[ki+1], angtol); + frac = 1.0/(double)cand[ki].cand_->numPoints(); + for (size_t kh=0; kh<dist_ang[ki+1].size(); ++kh) + { + avang[ki+1] += frac*dist_ang[ki+1][kh].second; + if (dist_ang[ki+1][kh].second <= angtol) + ang_in[ki+1]++; + } + + maxdist = std::max(maxdist, maxd[ki+1]); + avdist += (double)all_num[ki+1]*avd[ki+1]/(double)num; + num_inside += num_in[ki+1]; + num2_inside += num2_in[ki+1]; + meanang += (double)all_num[ki+1]*avang[ki+1]/(double)num; + inside_ang += ang_in[ki+1]; + } + int sf_flag = defineSfFlag(num, 0, tol, num_inside, num2_inside, avdist, + cyllike); +#ifdef DEBUG_GROW + std::ofstream of2("adj_source_reg.g2"); + for (size_t ki=0; ki<cand.size(); ++ki) + { + cand[ki].cand_->writeRegionPoints(of2); + } +#endif + + vector<size_t> out_cand; + for (size_t ki=0; ki<cand.size(); ++ki) + { + if (avd[ki+1] > tol3 || + (avd[ki+1] > tol && (double)ang_in[ki+1] < anglim*(double)all_num[ki+1])) + out_cand.push_back(ki); + } + + if (sf_flag >= ACCURACY_POOR && out_cand.size() == 0) + { + double max_av = avd[1]; + size_t ix = 0; + for (size_t ki=1; ki<cand.size(); ++ki) + if (avd[ki+1] > max_av) + { + max_av = avd[ki+1]; + ix = ki; + } + + out_cand.push_back(ix); + } + + if (out_cand.size() == 0) + { + // Integrate + for (size_t kh=0; kh<group_points_.size(); ++kh) + { + group_points_[kh]->setPar(Vector2D(parvals[0][2*kh],parvals[0][2*kh+1])); + group_points_[kh]->setSurfaceDist(dist_ang[0][kh].first, + dist_ang[0][kh].second); + } + for (size_t ki=0; ki<cand.size(); ++ki) + { + vector<RevEngRegion*> added_adjacent; + includeAdjacentRegion(cand[ki].cand_, maxd[ki+1], avd[ki+1], + num_in[ki+1], num2_in[ki+1], + parvals[ki+1], dist_ang[ki+1], added_adjacent); + grown_regions.push_back(cand[ki].cand_); + int num_sf = cand[ki].cand_->numSurface(); + for (int kb=0; kb<num_sf; ++kb) + adj_surfs.push_back(cand[ki].cand_->getSurface(kb)); + } + associated_sf_[0]->replaceSurf(merged1); + if (!merged1->isBounded()) + { + double diag = bbox_.low().dist(bbox_.high()); + associated_sf_[0]->limitSurf(2*diag); + } + updateInfo(tol, angtol); + setSurfaceFlag(sf_flag); + for (size_t kj=0; kj<rev_edges_.size(); ++kj) + rev_edges_[kj]->replaceSurf(this, merged1, tol); + + break; + } + else + { + for (int ka=(int)out_cand.size()-1; ka>=0; --ka) + cand.erase(cand.begin()+ka); + } + int stop_break0 = 1; + } + + int stop_break = 1; +} + + +//=========================================================================== +bool RevEngRegion::mergePlanarReg(double zero_H, double zero_K, double tol, + Point mainaxis[3], + vector<RevEngRegion*>& grown_regions) +//=========================================================================== +{ + if (!feasiblePlane(zero_H, zero_K)) + return false; +#ifdef DEBUG_MERGE + std::ofstream of1("source_planar_reg.g2"); + writeRegionPoints(of1); +#endif + + double anglim = 0.1*M_PI; //0.05; + vector<RevEngRegion*> merge_cand; + for (auto it=adjacent_regions_.begin(); it!=adjacent_regions_.end(); ++it) + { + if (!(*it)->feasiblePlane(zero_H, zero_K)) + continue; + if ((*it)->hasSurface()) + continue; + if ((*it)->hasAssociatedBlend()) + continue; + + Point norm = (*it)->getMeanNormal(); + double ang = avnorm_.angle(norm); + if (ang <= anglim) + merge_cand.push_back(*it); + } + + if (merge_cand.size() == 0) + return false; + +#ifdef DEBUG_MERGE + std::ofstream of2("adj_planar_reg.g2"); + for (size_t ki=0; ki<merge_cand.size(); ++ki) + merge_cand[ki]->writeRegionPoints(of2); +#endif + + // Check accuracy + vector<RevEngPoint*> all_pts; + all_pts.insert(all_pts.end(), group_points_.begin(), group_points_.end()); + for (size_t ki=0; ki<merge_cand.size(); ++ki) + all_pts.insert(all_pts.end(), merge_cand[ki]->pointsBegin(), + merge_cand[ki]->pointsEnd()); + shared_ptr<Plane> plane = computePlane(all_pts, avnorm_, mainaxis); + + double angtol = -1.0; + int min_pt = 2; // Not crucial here + double maxdist, avdist; + int num_in, num2_in; + vector<pair<double, double> > dist_ang; + vector<double> parvals; + vector<RevEngPoint*> inpt, outpt; + RevEngUtils::distToSurf(group_points_.begin(), group_points_.end(), + plane, tol, maxdist, avdist, num_in, num2_in, inpt, + outpt, parvals, dist_ang, angtol); + if (!accuracyOK(min_pt, tol, num_in, avdist)) + return false; + + for (int kj=(int)merge_cand.size()-1; kj>=0; --kj) + { + double maxdist2, avdist2; + int num_in2, num2_in2; + vector<pair<double, double> > dist_ang2; + vector<double> parvals2; + vector<RevEngPoint*> inpt2, outpt2; + RevEngUtils::distToSurf(merge_cand[kj]->pointsBegin(), + merge_cand[kj]->pointsEnd(), + plane, tol, maxdist2, avdist2, num_in2, num2_in2, inpt2, + outpt2, parvals2, dist_ang2, angtol); + if (!merge_cand[kj]->accuracyOK(0, tol, num_in2, avdist2)) + merge_cand.erase(merge_cand.begin()+kj); + } + if (merge_cand.size() == 0) + return false; + + // Include next layer of adjacent regions + vector<RevEngRegion*> adj_reg; + size_t cand_size = merge_cand.size(); + Point dir = plane->direction(); + for (size_t ki=0; ki<cand_size; ++ki) + { + for (auto it=merge_cand[ki]->adjacent_regions_.begin(); + it!=merge_cand[ki]->adjacent_regions_.end(); ++it) + { + if ((*it) == this) + continue; + if (!(*it)->feasiblePlane(zero_H, zero_K)) + continue; + if ((*it)->hasSurface()) + continue; + if ((*it)->hasAssociatedBlend()) + continue; + + size_t kr; + for (kr=0; kr<merge_cand.size(); ++kr) + if ((*it) == merge_cand[kr]) + break; + if (kr < merge_cand.size()) + continue; + + Point norm = (*it)->getMeanNormal(); + double ang = dir.angle(norm); + if (ang > anglim) + continue; + double maxdist3, avdist3; + int num_in3, num2_in3; + vector<pair<double, double> > dist_ang3; + vector<double> parvals3; + vector<RevEngPoint*> inpt3, outpt3; + RevEngUtils::distToSurf((*it)->pointsBegin(), + (*it)->pointsEnd(), + plane, tol, maxdist3, avdist3, num_in3, num2_in3, inpt3, + outpt3, parvals3, dist_ang3, angtol); + if ((*it)->accuracyOK(0, tol, num_in3, avdist3)) + merge_cand.push_back(*it); + } + } + +#ifdef DEBUG_MERGE + std::ofstream of3("adj_planar2_reg.g2"); + for (size_t ki=0; ki<merge_cand.size(); ++ki) + merge_cand[ki]->writeRegionPoints(of3); +#endif + + // Integrate identified regions + for (size_t ki=0; ki<merge_cand.size(); ++ki) + { + grown_regions.push_back(merge_cand[ki]); + for (auto it=merge_cand[ki]->adjacent_regions_.begin(); + it!=merge_cand[ki]->adjacent_regions_.end(); ++it) + { + if (*it != this) + { + addAdjacentRegion(*it); + (*it)->addAdjacentRegion(this); + (*it)->removeAdjacentRegion(merge_cand[ki]); + } + } + // for (size_t kj=ki+1; kj<merge_cand.size(); ++kj) + // if (merge_cand[kj]->isAdjacent(merge_cand[ki])) + // merge_cand[kj]->removeAdjacentRegion(merge_cand[ki]); + std::vector<std::pair<double, double> > dummy; + addRegion(merge_cand[ki], dummy); + removeAdjacentRegion(merge_cand[ki]); + } + + return true; +} + +//=========================================================================== +void RevEngRegion::mergeAdjacentSimilar(double tol, double angtol, + vector<RevEngRegion*>& grown_regions, + vector<HedgeSurface*>& adj_surfs, + vector<RevEngEdge*>& adj_edgs) +//=========================================================================== +{ + if (associated_sf_.size() == 0) + return; // No surface with which to check growt + + if (hasAssociatedBlend()) + return; + +#ifdef DEBUG_MERGE + std::ofstream of1("source_group.g2"); + writeRegionPoints(of1); +#endif + int sfcode; + ClassType classtype = associated_sf_[0]->instanceType(sfcode); + bool cyllike = (classtype == Class_Cylinder || classtype == Class_Cone); + //HedgeSurface *hedge = associated_sf_[0]; + vector<RevEngRegion*> adj_reg; + vector<double> score; + double frac2 = 0.75; + double frac3 = 2.0; + for (auto it=adjacent_regions_.begin(); it!=adjacent_regions_.end(); ++it) + { + if ((*it)->hasSurface() && (!(*it)->hasAssociatedBlend())) + { + double curr_score; + bool compatible = associated_sf_[0]->isCompatible((*it)->getSurface(0), + angtol, tol, + classtype, curr_score); + if (compatible) + { + adj_reg.push_back(*it); + score.push_back(curr_score); + } + } + } + + if (adj_reg.size() == 0) + return; // Nothing with which to merge + +#ifdef DEBUG_MERGE + std::ofstream of2("adj_group.g2"); + for (size_t ki=0; ki<adj_reg.size(); ++ki) + adj_reg[ki]->writeRegionPoints(of2); +#endif + for (size_t ki=0; ki<adj_reg.size(); ++ki) + for (size_t kj=ki+1; kj<adj_reg.size(); ++kj) + if (score[kj] > score[ki]) + { + std::swap(score[ki], score[kj]); + std::swap(adj_reg[ki], adj_reg[kj]); + } + + shared_ptr<ParamSurface> surf; + int ka; + double maxdist=0.0, avdist=0.0; + int num_in = 0; + vector<double> maxd(adj_reg.size()+1, 0.0); + vector<double> avd(adj_reg.size()+1, 0.0); + vector<int> ninside(adj_reg.size()+1, 0); + vector<int> ninside2(adj_reg.size()+1, 0); + vector<vector<double> > parvals(adj_reg.size()+1); + vector<vector<pair<double,double> > > dist_ang(adj_reg.size()+1); + for (ka=(int)adj_reg.size(); ka>=1; --ka) + { + // Create surface from combined point set + vector<pair<vector<RevEngPoint*>::iterator, + vector<RevEngPoint*>::iterator> > points; + BoundingBox bbox(3); + vector<int> nmbpts; + + nmbpts.push_back(numPoints()); + points.push_back(std::make_pair(pointsBegin(), pointsEnd())); + bbox = boundingBox(); + + for (int kb=0; kb<ka; ++kb) + { + nmbpts.push_back(adj_reg[kb]->numPoints()); + points.push_back(std::make_pair(adj_reg[kb]->pointsBegin(), + adj_reg[kb]->pointsEnd())); + bbox.addUnionWith(adj_reg[kb]->boundingBox()); + } + + int num_all = 0; + for (int kb=0; kb<=ka; ++kb) + num_all += nmbpts[kb]; + double frac = 1.0/(double)num_all; + if (classtype == Class_Plane) + { + surf = RevEngUtils::doMergePlanes(points, bbox, nmbpts); + } + else if (classtype == Class_Cylinder) + { + surf = RevEngUtils::doMergeCylinders(points, bbox, nmbpts); + } + else if (classtype == Class_Sphere) + { + Point normal = frac*numPoints()*avnorm_; + + for (int kb=1; kb<=ka; ++kb) + normal += frac*adj_reg[kb-1]->numPoints()*adj_reg[kb-1]->getMeanNormal(); + normal.normalize_checked(); + surf = RevEngUtils::doMergeSpheres(points, bbox, nmbpts, normal); + } + else if (classtype == Class_Torus) + { + surf = RevEngUtils::doMergeTorus(points, bbox, nmbpts); + } + if (!surf.get()) + continue; + + // Check accuracy +#ifdef DEBUG_GROW + std::ofstream of("in_out_adj.g2"); +#endif + maxdist = avdist = 0.0; + num_in = 0; + int num2_in = 0; + vector<int> sfflag(ka+1, NOT_SET); + bool flagOK = true; + for (int kb=0; kb<=ka; ++kb) + { + maxd[kb] = avd[kb] = 0.0; + ninside[kb] = ninside2[kb] = 0; + parvals[kb].clear(); + dist_ang[kb].clear(); + vector<RevEngPoint*> in, out; + RevEngUtils::distToSurf(points[kb].first, points[kb].second, surf, tol, + maxd[kb], avd[kb], ninside[kb], ninside2[kb], + in, out, parvals[kb], + dist_ang[kb], angtol); + maxdist = std::max(maxdist, maxd[kb]); + avdist += frac*nmbpts[kb]*avd[kb]; + num_in += ninside[kb]; + num2_in += ninside2[kb]; + RevEngRegion *curr = (kb==0) ? this : adj_reg[kb-1]; + sfflag[kb] = curr->defineSfFlag(0, tol, ninside[kb], ninside2[kb], + avd[kb], cyllike); + if (sfflag[kb] == NOT_SET) + flagOK = false; + +#ifdef DEBUG_GROW + of << "400 1 0 4 255 0 0 255" << std::endl; + of << in.size() << std::endl; + for (size_t kj=0; kj<in.size(); ++kj) + of << in[kj]->getPoint() << std::endl; + of << "400 1 0 4 0 255 0 255" << std::endl; + of << out.size() << std::endl; + for (size_t kj=0; kj<out.size(); ++kj) + of << out[kj]->getPoint() << std::endl; +#endif + } + + int num = numPoints(); + double init_max = frac*num*maxdist_; + double init_av = frac*num*avdist_; + int init_in = num_inside_; + int init_in2 = num_inside2_; + for (int kb=0; kb<ka; ++kb) + { + int num2 = adj_reg[kb]->numPoints(); + double max2, av2; + int num_in2, num2_in2; + adj_reg[kb]->getAccuracy(max2, av2, num_in2, num2_in2); + init_max += frac*num2*max2; + init_av += frac*num2*av2; + init_in += num_in2; + init_in2 += num2_in2; + } + if (flagOK && num2_in > num_all/2 && avdist < tol && + (double)num2_in > frac2*(double)init_in2 /*&& + (avdist < frac3*init_av || avdist < frac2*tol)*/) + break; + + // Swap adjacent regions to skip the least accurate region + if (ka > 1 && avd[1] > avd[ka]) // The test should be made more accurate + { + std::swap(adj_reg[0], adj_reg[ka-1]); + std::swap(score[0], score[ka-1]); + } + } + + if (!surf.get()) + return; + if (ka >= 1) + { + setAccuracy(maxd[0], avd[0], ninside[0], ninside2[0]); + for (size_t ki=0; ki<group_points_.size(); ++ki) + { + group_points_[ki]->setPar(Vector2D(parvals[0][2*ki],parvals[0][2*ki+1])); + group_points_[ki]->setSurfaceDist(dist_ang[0][ki].first, dist_ang[0][ki].second); + } + + for (int kb=0; kb<ka; ++kb) + { + vector<RevEngRegion*> added_adjacent; + includeAdjacentRegion(adj_reg[kb], maxd[kb+1], avd[kb+1], ninside[kb+1], + ninside2[kb+1], parvals[kb+1], + dist_ang[kb+1], added_adjacent); + grown_regions.push_back(adj_reg[kb]); + int num_sf = adj_reg[kb]->numSurface(); + for (int kc=0; kc<num_sf; ++kc) + adj_surfs.push_back(adj_reg[kb]->getSurface(kc)); + vector<RevEngEdge*> rev_edgs = adj_reg[kb]->getAllRevEdges(); + for (size_t kr=0; kr<rev_edgs.size(); ++kr) + { + RevEngRegion *adj1, *adj2; + rev_edgs[kr]->getAdjacent(adj1, adj2); + RevEngRegion *other = (adj1 == adj_reg[kb]) ? adj2 : adj1; + other->removeRevEngEdge(rev_edgs[kr]); + } + adj_edgs.insert(adj_edgs.end(), rev_edgs.begin(), rev_edgs.end()); + removeAdjacentRegion(adj_reg[kb]); + } + updateInfo(tol, angtol); + double maxdist2, avdist2; + int num_in2, num2_in2; + getAccuracy(maxdist2, avdist2, num_in2, num2_in2); + int surfflag = defineSfFlag(0, tol, num_in2, num2_in2, avdist2, cyllike); + setSurfaceFlag(surfflag); + associated_sf_[0]->replaceSurf(surf); + computeDomain(); + } + +} + +//=========================================================================== +void +RevEngRegion::includeAdjacentRegion(RevEngRegion* reg, double maxd, double avd, + int num_inside, int num_inside2, + vector<double>& parvals, + vector<pair<double, double> >& dist_ang, + vector<RevEngRegion*>& added_adjacent) +//=========================================================================== +{ + // First update parameter values + size_t kr=0; + for (auto it1=reg->pointsBegin(); it1!=reg->pointsEnd(); ++it1, kr+=2) + { + (*it1)->addMove(); + (*it1)->setPar(Vector2D(parvals[kr],parvals[kr+1])); + } + addRegion(reg, dist_ang, maxd, avd, num_inside, num_inside2); + + + // Update adjacent regions + for (auto it2=reg->adjacent_regions_.begin(); it2!=reg->adjacent_regions_.end(); ++it2) + { + if (*it2 != this) + { + size_t nmb_adj = adjacent_regions_.size(); + addAdjacentRegion(*it2); + if (adjacent_regions_.size() > nmb_adj) + { + added_adjacent.push_back(*it2); + (*it2)->addAdjacentRegion(this); + } + (*it2)->removeAdjacentRegion(reg); + } + } +} + +//=========================================================================== +void RevEngRegion::checkEdgeAssociation(double tol, int min_point_reg, + vector<HedgeSurface*>& removed_sfs) +//=========================================================================== +{ + vector<RevEngRegion*> adj_regs(adjacent_regions_.begin(), adjacent_regions_.end()); + std::set<RevEngEdge*> rev_edgs; + for (size_t ki=0; ki<adj_regs.size(); ++ki) + if (adj_regs[ki]->hasRevEdges()) + { + vector<RevEngEdge*> curr_edgs = adj_regs[ki]->getAllRevEdges(); + rev_edgs.insert(curr_edgs.begin(), curr_edgs.end()); + } + vector<RevEngEdge*> edges(rev_edgs.begin(), rev_edgs.end()); + for (size_t ki=0; ki<edges.size(); ++ki) + { + vector<RevEngRegion*> blend_regs; + edges[ki]->getAllBlendRegs(blend_regs); + size_t kj = 0; + for (kj=0; kj<blend_regs.size(); ++kj) + if (blend_regs[kj]->isAdjacent(this)) + { + //std::cout << "Potential edge" << std::endl; + vector<shared_ptr<CurveOnSurface> > cvs; + edges[ki]->getCurve(cvs); + double width = edges[ki]->getDistance(); + int num_in_blend = 0; + if (isInBlend(cvs, 2.0*width, tol, num_in_blend)) + { + edges[ki]->addBlendRegion(this); + setAssociatedBlend(edges[ki]); + } + else if (num_in_blend > 0 && (int)group_points_.size() < min_point_reg) + { + // Dubious surface + if (associated_sf_.size() > 0) + removed_sfs.insert(removed_sfs.end(), associated_sf_.begin(), + associated_sf_.end()); + clearSurface(); + } + break; + } + if (kj < blend_regs.size()) + break; + } + int stop_break = 1; +} + +//=========================================================================== + +void endPoints(vector<RevEngPoint*>& seq_pts, RevEngPoint*& end1, + RevEngPoint*& end2) +{ + size_t ix1 = 0, ix2 = 1; + ix2 = std::min(ix2, seq_pts.size()-1); + double maxlen = seq_pts[ix1]->pntDist(seq_pts[ix2]); + for (size_t ki=0; ki<seq_pts.size(); ++ki) + for (size_t kj=ki+1; kj<seq_pts.size(); ++kj) + { + double len = seq_pts[ki]->pntDist(seq_pts[kj]); + if (len > maxlen) + { + maxlen = len; + ix1 = ki; + ix2 = kj; + } + } + end1 = seq_pts[ix1]; + end2 = seq_pts[ix2]; +} + +void getBranches(vector<vector<RevEngPoint*> >& bd_pts, + vector<vector<pair<RevEngPoint*,int> > >& branches) +{ + RevEngPoint *dummy = 0; + branches.resize(bd_pts.size()); + for (size_t ki=0; ki<bd_pts.size(); ++ki) + { + for (size_t kr=ki+1; kr<bd_pts.size(); ++kr) + { + for (size_t kj=0; kj<bd_pts[ki].size(); ++kj) + { + for (size_t kh=0; kh<bd_pts[kr].size(); ++kh) + { + if (bd_pts[ki][kj]->isNeighbour(bd_pts[kr][kh])) + { + branches[ki].push_back(std::make_pair(bd_pts[ki][kj],(int)kr)); + branches[kr].push_back(std::make_pair(bd_pts[kr][kh],(int)ki)); + } + } + } + } + if (branches[ki].size() == 0) + branches[ki].push_back(std::make_pair(dummy,-1)); + } +} + +int getNextSeq(vector<int>& prev, int curr, + vector<vector<pair<RevEngPoint*,int> > >& branches, + vector<vector<RevEngPoint*> >& bd_pts, + RevEngPoint*& pnt) +{ + vector<pair<RevEngPoint*,int> > cand; + for (size_t ki=0; ki<branches[curr].size(); ++ki) + { + size_t kj; + for (kj=0; kj<prev.size(); ++kj) + if (branches[curr][ki].second == prev[kj]) + break; + if (kj < prev.size()) + continue; + for (kj=0; kj<cand.size(); ++kj) + if (cand[kj].first == branches[curr][ki].first && + cand[kj].second == branches[curr][ki].second) + break; + if (kj == cand.size()) + cand.push_back(branches[curr][ki]); + } + + // Sort candidates + for (size_t ki=0; ki<cand.size(); ++ki) + for (size_t kj=ki+1; kj<cand.size(); ++kj) + if (cand[kj].second < cand[ki].second) + std::swap(cand[kj], cand[ki]); + + // Select one candidate for each adjacent curve + vector<double> dist; + for (size_t ki=0; ki<cand.size(); ) + { + size_t kj; + for (kj=ki+1; + kj<cand.size() && cand[kj].second == cand[ki].second; ++kj); + + int kr = cand[ki].second; + double mindist = std::numeric_limits<double>::max(); + int ix = -1; + if (kr >= 0) + { + for (size_t kh=ki; kh<kj; ++kh) + { + for (size_t kv=0; kv<branches[kr].size(); ++kv) + { + if (branches[kr][kv].second != curr) + continue; + double dd = cand[kh].first->pntDist(branches[kr][kv].first); + if (dd < mindist) + { + mindist = dd; + ix = (int)kh; + } + } + } + } + for (int ka=(int)kj-1; ka>=(int)ki; --ka) + { + if (ka != ix) + cand.erase(cand.begin()+ka); + } + if (ix >= 0) + { + dist.push_back(mindist); + ++ki; + } + } + + if (cand.size() == 0) + return -1; + + // Select adjacent branch + int ix = 0; + double mindist = dist[0]; + double eps = 1.0e-9; + for (size_t ki=1; ki<cand.size(); ++ki) + { + if (fabs(dist[ki] - mindist) < eps) + { + int num1 = (int)bd_pts[ix].size(); + int num2 = (int)bd_pts[ki].size(); + if (num2 > num1) + { + ix = (int)ki; + mindist= dist[ki]; + } + } + else if (dist[ki] < mindist) + { + ix = (int)ki; + mindist= dist[ki]; + } + } + pnt = cand[ix].first; + return cand[ix].second; +} + +void splitAtSeam(shared_ptr<ParamSurface>& surf, shared_ptr<ParamCurve>& cv, + double tol, double angtol, double maxlim, + vector<shared_ptr<ParamCurve> >& subcvs) +{ + vector<Point> pos; + vector<Point> norm; + vector<Point> axis; + vector<int> type; // 1=cylinder, 2=cone, 3=torus big, 4=torus small, 5=sphere + shared_ptr<ElementarySurface> elemsf = + dynamic_pointer_cast<ElementarySurface,ParamSurface>(surf); + double radius = elemsf->radius(0,0); + RectDomain dom = surf->containingDomain(); + if (surf->instanceType() == Class_Cylinder || + surf->instanceType() == Class_Cone || + surf->instanceType() == Class_Sphere) + { + vector<Point> seam_pt(3); + surf->point(seam_pt, dom.umin(), 0.5*(dom.vmin()+dom.vmax()), 1); + pos.push_back(seam_pt[0]); + seam_pt[1].normalize(); + norm.push_back(seam_pt[1]); + axis.push_back(elemsf->direction()); + type.push_back((surf->instanceType() == Class_Cylinder) ? 1 : + ((surf->instanceType() == Class_Cone) ? 2 : 3)); + } + else if (surf->instanceType() == Class_Torus) + { + shared_ptr<Torus> tor = dynamic_pointer_cast<Torus,ParamSurface>(surf); + Point centre = tor->location(); + Point dir = tor->direction(); + vector<Point> seam_pt(3); + surf->point(seam_pt, dom.umin(), dom.vmin(), 1); + seam_pt[1].normalize(); + + pos.push_back(centre); + norm.push_back(dir); + axis.push_back(seam_pt[1]); + type.push_back(3); + + pos.push_back(seam_pt[0]); + norm.push_back(seam_pt[1]); + axis.push_back(dir); + type.push_back(4); + } + + double eps = std::min(tol, 1.0e-5); + vector<double> splitpar; + for (size_t ki=0; ki<pos.size(); ++ki) + { + vector<double> intpar; + vector<pair<double,double> > intcvs; + intersectCurvePlane(cv.get(), pos[ki], norm[ki], eps, + intpar, intcvs); + for (size_t kr=0; kr<intcvs.size(); ++kr) + { + intpar.push_back(intcvs[kr].first); + intpar.push_back(intcvs[kr].second); + } + + for (size_t kr=0; kr<intpar.size(); ++kr) + { + // Check if the intersection is at the seam + Point pt = cv->point(intpar[kr]); + Point dir = axis[ki]; + double rad = radius; + if (type[ki] == 2) + { + shared_ptr<Cone> cone = dynamic_pointer_cast<Cone, ParamSurface>(surf); + double upar, vpar, dist; + Point close; + cone->closestPoint(pt, upar, vpar, close, dist, eps); + rad = cone->radius(vpar, 0.0); + shared_ptr<Line> line = cone->getLine(upar); + dir = line->getDirection(); + } + double dd = pt.dist(pos[ki]); + double dd2 = fabs((pt - pos[ki])*dir); + double dd3 = (pt - pos[ki])*norm[ki]; + if (dd-dd2 < rad && dd3 < tol) + splitpar.push_back(intpar[kr]); // Will need to consider for + // surfaces different from cylinder + } + } + if (splitpar.size() > 1) + { + std::sort(splitpar.begin(), splitpar.end()); + for (int ka=(int)splitpar.size()-1; ka>0; --ka) + if (splitpar[ka] - splitpar[ka-1] < eps) + { + splitpar[ka-1] = 0.5*(splitpar[ka-1] + splitpar[ka]); + splitpar.erase(splitpar.begin()+ka); + } + } + + shared_ptr<ParamCurve> tmpcv = cv; + for (size_t ki=0; ki<splitpar.size(); ++ki) + { + vector<shared_ptr<ParamCurve> > split = tmpcv->split(splitpar[ki]); + subcvs.push_back(split[0]); + tmpcv = split[1]; + } + subcvs.push_back(tmpcv); + int stop_all = 1; + + // shared_ptr<ElementarySurface> elemsf = + // dynamic_pointer_cast<ElementarySurface, ParamSurface>(surf); + // if (elemsf.get()) + // { + // bool close_u, close_v; + // elemsf->isClosed(close_u, close_v); + // vector<shared_ptr<ParamCurve> > seam_cvs; + // vector<int> dir; + // if (close_u) + // { + // vector<shared_ptr<ParamCurve> > tmp_cvs = + // elemsf->constParamCurves(dom.umin(), false); + // seam_cvs.push_back(tmp_cvs[0]); + // dir.push_back(1); + // } + // if (close_v) + // { + // vector<shared_ptr<ParamCurve> > tmp_cvs = + // elemsf->constParamCurves(dom.vmin(), true); + // seam_cvs.push_back(tmp_cvs[0]); + // dir.push_back(2); + // } + + // double eps = std::max(1.0e-4, 0.001*(cv->endparam()-cv->startparam())); + // subcvs.push_back(cv); + // for (size_t kj=0; kj<subcvs.size(); ) + // { + // bool atseam = false; + // for (size_t ki=0; ki<seam_cvs.size(); ++ki) + // { + // double par1, par2, dist; + // Point close1, close2; + // ClosestPoint::closestPtCurves(subcvs[kj].get(), seam_cvs[ki].get(), + // par1, par2, dist, close1, close2); + // if (dist > maxlim) + // continue; + // if (par1 < subcvs[kj]->startparam()+eps || + // par1 > subcvs[kj]->endparam()-eps) + // continue; + + // // Check angle with surface normal + // double sf_u = (dir[ki] == 1) ? dom.umin() : par2; + // double sf_v = (dir[ki] == 1) ? par2 : dom.vmin(); + // Point norm; + // surf->normal(norm, sf_u, sf_v); + // Point vec = close2 - close1; + // double ang = norm.angle(vec); + // ang = std::min(ang, M_PI-ang); + // if (ang < angtol) + // { + // vector<shared_ptr<ParamCurve> > split = + // subcvs[kj]->split(par1); + // subcvs[kj] = split[0]; + // subcvs.insert(subcvs.end(), split.begin()+1, split.end()); + // atseam = true; + // break; + // } + // } + // if (!atseam) + // ++kj; + // } + // } + // else + // subcvs.push_back(cv); +} + + +void RevEngRegion::extendBoundaries(double mean_edge_len, int min_point_reg, + double tol, double angtol, Point mainaxis[3]) +//=========================================================================== +{ + +#ifdef DEBUG_ADJUST + std::ofstream of1("curr_regions_adjust.g2"); + std::ofstream of11("par_cvs_in.g2"); + writeRegionPoints(of1); + for (size_t ki=0; ki<trim_edgs_.size(); ++ki) + { + shared_ptr<ParamCurve> cv = trim_edgs_[ki]->geomCurve(); + shared_ptr<CurveOnSurface> sfcv = + dynamic_pointer_cast<CurveOnSurface,ParamCurve>(cv); + if (sfcv.get()) + { + sfcv->spaceCurve()->writeStandardHeader(of1); + sfcv->spaceCurve()->write(of1); + if (sfcv->hasParameterCurve()) + SplineDebugUtils::writeSpaceParamCurve(sfcv->parameterCurve(),of11); + } + } +#endif + + int min_nmb_adj = min_point_reg/10; + size_t min_bd = min_point_reg/50; + double min_len = 20.0*mean_edge_len; +#ifdef DEBUG_ADJUST + std::ofstream of5("all_adj_adjust.g2"); + for (auto it=adjacent_regions_.begin(); it!=adjacent_regions_.end(); ++it) + { + if (commonRevEdge(*it)) + continue; + + if (commonTrimEdge(*it)) + continue; + + if ((*it)->hasBlendEdge()) + continue; // Trimming curves should exist already + // if ((*it)->numPoints() < min_nmb) + // continue; + (*it)->writeRegionPoints(of5); + } +#endif + + vector<vector<RevEngPoint*> > bd_pts1; //, bd_pts2; + vector<RevEngRegion*> adj_bd; + vector<pair<RevEngPoint*,RevEngPoint*> > end_pts; + for (auto it=adjacent_regions_.begin(); it!=adjacent_regions_.end(); ++it) + { + if (commonRevEdge(*it)) + continue; + + if (commonTrimEdge(*it)) + continue; + + if ((*it)->hasBlendEdge()) + continue; // Trimming curves should exist already + + // The boundary towards adjacent regions with a surface should preferably be + // handled by other tools, but are currently included + // if ((*it)->hasSurface()) + // continue; + // if ((*it)->numPoints() < min_nmb) + // continue; + +// #ifdef DEBUG_ADJUST +// std::ofstream of2("adj_regions_adjust.g2"); +// (*it)->writeRegionPoints(of2); +// #endif + + // Get boundary points + // Dismiss boundary points that are too close to existing trimming curves + vector<RevEngPoint*> adj_pts1 = extractNextToAdjacent(*it); + int nmb_lim = (int)adj_pts1.size()/10; + int nmb_in = 0; + for (size_t kj=0; kj<adj_pts1.size(); ++kj) + { + Vector3D xyz = adj_pts1[kj]->getPoint(); + Point pnt(xyz[0], xyz[1], xyz[2]); + for (size_t ki=0; ki<trim_edgs_.size(); ++ki) + { + shared_ptr<ParamCurve> cv = trim_edgs_[ki]->geomCurve(); + double tpar, dist; + Point close; + cv->closestPoint(pnt, cv->startparam(), cv->endparam(), tpar, close, dist); + if (dist <= tol) + { + nmb_in++; + break; + } + } + } + + //vector<RevEngPoint*> adj_pts2 = (*it)->extractNextToAdjacent(this); + if (nmb_in < nmb_lim) + { + RevEngPoint *end1, *end2; + RevEngPoint *dummy = 0; + vector<RevEngPoint*> tmp_pts; + for (size_t kj=0; kj<adj_pts1.size(); ++kj) + if (adj_pts1[kj]->getSurfaceDist() <= tol) + tmp_pts.push_back(adj_pts1[kj]); + bd_pts1.push_back(tmp_pts); //adj_pts1); + adj_bd.push_back(*it); + if (adj_pts1.size() > 0) + { + endPoints(adj_pts1, end1, end2); + end_pts.push_back(std::make_pair(end1, end2)); + } + else + end_pts.push_back(std::make_pair(dummy, dummy)); + } + //bd_pts2.push_back(adj_pts2); + } + // if (adj_pts1.size() < min_bd || adj_pts2.size() < min_bd) + // continue; + + + vector<vector<pair<RevEngPoint*,int> > > branches; + getBranches(bd_pts1, branches); + +#ifdef DEBUG_ADJUST + std::ofstream of2("bd1.g2"); + std::ofstream of4("end1.g2"); + for (size_t kj=0; kj<bd_pts1.size(); ++kj) + if (bd_pts1[kj].size() > 0) + { + of4 << "400 1 0 4 255 0 0 255" << std::endl; + of4 << "2" << std::endl; + of4 << end_pts[kj].first->getPoint() << std::endl; + of4 << end_pts[kj].second->getPoint() << std::endl; + of2 << "400 1 0 4 0 255 0 255" << std::endl; + of2 << bd_pts1[kj].size() << std::endl; + for (size_t ki=0; ki<bd_pts1[kj].size(); ++ki) + of2 << bd_pts1[kj][ki]->getPoint() << std::endl; + } + + // std::ofstream of3("bd2.g2"); + // for (size_t kj=0; kj<bd_pts2.size(); ++kj) + // if (bd_pts2[kj].size() > 0) + // { + // of3 << "400 1 0 4 0 255 0 255" << std::endl; + // of3 << bd_pts2[kj].size() << std::endl; + // for (size_t ki=0; ki<bd_pts2[kj].size(); ++ki) + // of3 << bd_pts2[kj][ki]->getPoint() << std::endl; + // } + + std::ofstream of6("bd_branches.g2"); + for (size_t ki=0; ki<branches.size(); ++ki) + if (branches[ki].size() > 0 && branches[ki][0].first) + { + of6 << "400 1 0 4 255 0 0 255" << std::endl; + of6 << branches[ki].size() << std::endl; + for (size_t kj=0; kj<branches[ki].size(); ++kj) + of6 << branches[ki][kj].first->getPoint() << std::endl; + } +#endif + + // Sort sequences and remember branch points + vector<vector<int> > ixs; + vector<vector<RevEngPoint*> > joints; + vector<int> num_bd; + for (size_t ki=0; ki<branches.size(); ++ki) + { + size_t kr,kh; + for (kr=0; kr<ixs.size(); ++kr) + { + for (kh=0; kh<ixs[kr].size(); ++kh) + { + if (ixs[kr][kh] == (int)ki) + break; + } + if (kh < ixs[kr].size()) + break; + } + if (kr < ixs.size()) + continue; + + if (branches[ki].size() == 0) + continue; + + vector<int> ixs0; + vector<RevEngPoint*> joints0; + ixs0.push_back((int)ki); + int curr=(int)ki, next=-1; + RevEngPoint *pt; + int num0 = 0; + next = getNextSeq(ixs0, curr, branches, bd_pts1, pt); + while (next >= 0) + { + ixs0.push_back(next); + joints0.push_back(pt); + num0 += (int)branches[curr].size(); + curr = next; + next = getNextSeq(ixs0, curr, branches, bd_pts1, pt); + } + if (ixs0.size() > 1) + { + curr = ixs0[0]; + next = getNextSeq(ixs0, curr, branches, bd_pts1, pt); + while (next >= 0) + { + ixs0.insert(ixs0.begin(), next); + joints0.insert(joints0.begin(), pt); + num0 += (int)branches[curr].size(); + curr = next; + next = getNextSeq(ixs0, curr, branches, bd_pts1, pt); + } + } + ixs.push_back(ixs0); + joints.push_back(joints0); + num_bd.push_back(num0); + } + + for (size_t ki=0; ki<ixs.size(); ++ki) + for (size_t kj=ki+1; kj<ixs.size(); ++kj) + if (num_bd[kj] > num_bd[ki]) + { + std::swap(ixs[ki], ixs[kj]); + std::swap(joints[ki], joints[kj]); + std::swap(num_bd[ki], num_bd[kj]); + } + +#ifdef DEBUG_ADJUST + std::ofstream of7("joined_seqs.g2"); + for (size_t ki=0; ki<ixs.size(); ++ki) + { + int num=0; + for (size_t kj=0; kj<ixs[ki].size(); ++kj) + num += (int)bd_pts1[ixs[ki][kj]].size(); + + of7 << "400 1 0 0" << std::endl; + of7 << num << std::endl; + for (size_t kj=0; kj<ixs[ki].size(); ++kj) + for (size_t kr=0; kr<bd_pts1[ixs[ki][kj]].size(); ++kr) + of7 << bd_pts1[ixs[ki][kj]][kr]->getPoint() << std::endl; + } +#endif + + // Check if the points can be approximated by a circle or a line + // First collect seqences + vector<bool> done(ixs.size(), false); + vector<vector<size_t> > all_bd_ixs; + vector<int> all_num; + vector<vector<Point> > all_points; + vector<int> all_adj_num; + vector<Point> all_norm; + for (size_t ki=0; ki<ixs.size(); ++ki) + { + if (done[ki]) + continue; + + // Collect points + vector<size_t> bd_ixs; + size_t kj=ki; + int num = 0; + while (kj < ixs.size()) + { + done[kj] = true; + for (size_t kr=0; kr<ixs[kj].size(); ++kr) + { + size_t kh; + for (kh=0; kh<bd_ixs.size(); ++kh) + if (bd_ixs[kh] == ixs[kj][kr]) + break; + if (kh == bd_ixs.size()) + { + bd_ixs.push_back(ixs[kj][kr]); + num += (int)bd_pts1[ixs[kj][kr]].size(); + } + } + + for (++kj; kj<ixs.size(); ++kj) + { + size_t kr; + for (kr=0; kr<ixs[kj].size(); ++kr) + { + size_t kh; + for (kh=0; kh<bd_ixs.size(); ++kh) + if (bd_ixs[kh] == ixs[kj][kr]) + break; + if (kh < bd_ixs.size()) + break; + } + if (kr < ixs[kj].size()) + break; + } + } + + vector<Point> points; + points.reserve(num); + Point norm(0.0, 0.0, 0.0); + double fac = 1.0/(double)num; + int num_adj = 0; + for (size_t kr=0; kr<bd_ixs.size(); ++kr) + { + for (size_t kh=0; kh<bd_pts1[bd_ixs[kr]].size(); ++kh) + { + Vector3D xyz = bd_pts1[bd_ixs[kr]][kh]->getPoint(); + points.push_back(Point(xyz[0], xyz[1], xyz[2])); + Point norm0 = bd_pts1[bd_ixs[kr]][kh]->getTriangNormal(); + norm += fac*norm0; + } + num_adj += adj_bd[bd_ixs[kr]]->numPoints(); + } + all_bd_ixs.push_back(bd_ixs); + all_num.push_back(num); + all_points.push_back(points); + all_norm.push_back(norm); + all_adj_num.push_back(num_adj); + } + + int num_lim = 10; + vector<shared_ptr<ElementaryCurve> > elemcv(2*all_points.size()); + for (size_t ki=0; ki<all_points.size(); ++ki) + { + if (all_points[ki].size() < num_lim) + continue; + + // Compute circle + Point pos0, axis, Cx, Cy; + RevEngUtils::computePlane(all_points[ki], all_norm[ki], mainaxis, + pos0, axis, Cx, Cy); + + Point centre; + double radius; + try { + RevEngUtils::computeCircPosRadius(all_points[ki], axis, Cx, Cy, + centre, radius); + } + catch (...) + { + continue; + } + + shared_ptr<Circle> circ(new Circle(radius, centre, axis, Cx)); + elemcv[2*ki] = circ; + + // Compute line + Point mid, dir; + RevEngUtils::computeLine(all_points[ki], mid, dir); + shared_ptr<Line> line(new Line(mid, dir)); + elemcv[2*ki+1] = line; + + int stop_circ = 1; + } +#ifdef DEBUG_ADJUST + std::ofstream of8("circle_line.g2"); + for (size_t ki=0; ki<elemcv.size(); ++ki) + { + if (elemcv[ki].get()) + { + elemcv[ki]->writeStandardHeader(of8); + elemcv[ki]->write(of8); + } + } +#endif + + // Check distance + vector<double> maxdist(all_points.size(), std::numeric_limits<double>::max()); + vector<double> avdist(all_points.size(), std::numeric_limits<double>::max()); + vector<int> num_inside(all_points.size(), 0); + vector<vector<double> > param(all_points.size()); + vector<vector<double> > distance(all_points.size()); + vector<int> match(all_points.size(), -1); + + double fac1 = 0.9; + for (size_t ki=0; ki<all_points.size(); ++ki) + { + if (all_points[ki].size() < num_lim) + continue; + for (size_t kj=0; kj<elemcv.size(); ++kj) + { + if (!elemcv[kj].get()) + continue; + double maxd, avd; + int in; + vector<double> parvals, dist; + RevEngUtils::distToCurve(all_points[ki], elemcv[kj], tol, maxd, + avd, in, parvals, dist); + if ((avd < avdist[ki] && + ((double)in > fac1*(double)num_inside[ki] || num_inside[ki] == 0)) || + (in > num_inside[ki] && fac1*avd < avdist[ki]) ) + { + maxdist[ki] = maxd; + avdist[ki] = avd; + num_inside[ki] = in; + param[ki] = parvals; + distance[ki] = dist; + match[ki] = (int)kj; + } + } + int stop_dist = 1; + } + +#ifdef DEBUG_ADJUST + std::ofstream of9("spline.g2"); +#endif + + shared_ptr<ParamSurface> surf = getSurface(0)->surface(); + double smoothwgt = 0.5; + int in=6, ik=4; + int maxiter = 2; +#ifdef DEBUG_ADJUST + std::ofstream of10("proj_cvs.g2"); + surf->writeStandardHeader(of10); + surf->write(of10); +#endif + for (size_t kj=0; kj<elemcv.size(); ++kj) + { + if (!elemcv[kj].get()) + continue; + + // Collect points associated to this curve + vector<int> pt_ix; + for (size_t ki=0; ki<match.size(); ++ki) + if (match[ki] == (int)kj) + pt_ix.push_back((int)ki); + + if (pt_ix.size() == 0) + continue; + + vector<Point> pts; + vector<double> pts2; + vector<double> par; + int curr_adj_num = 0; + for (size_t ki=0; ki<pt_ix.size(); ++ki) + { + pts.insert(pts.end(), all_points[pt_ix[ki]].begin(), + all_points[pt_ix[ki]].end()); + par.insert(par.end(), param[pt_ix[ki]].begin(), param[pt_ix[ki]].end()); + curr_adj_num += all_adj_num[pt_ix[ki]]; + } + + // Check significance of current boundary points + if ((int)pts.size() < min_bd || curr_adj_num < min_nmb_adj) + continue; + + for (size_t ki=0; ki<par.size(); ++ki) + for (size_t kr=ki+1; kr<par.size(); ++kr) + if (par[kr] < par[ki]) + { + std::swap(par[kr], par[ki]); + std::swap(pts[kr], pts[ki]); + } + + bool close = false; + if (kj%2 == 0) + { + // Circular base curve. Check for internal seam + double closefac = 0.1*M_PI; + double avdd = 2*M_PI/(double)(par.size()-1); + double ddlim = 20.0*avdd; + double maxdd = 0; + size_t max_ix = 0; + for (size_t ki=1; ki<par.size(); ++ki) + if (par[ki] - par[ki-1] > maxdd) + { + maxdd = par[ki] - par[ki-1]; + max_ix = ki; + } + if (max_ix > 0 && maxdd > ddlim) + { + size_t nn = par.size()-max_ix; + par.insert(par.end(), par.begin(), par.begin()+max_ix); + pts.insert(pts.end(), pts.begin(), pts.begin()+max_ix); + par.erase(par.begin(), par.begin()+max_ix); + pts.erase(pts.begin(), pts.begin()+max_ix); + for (size_t kr=nn; kr<par.size(); ++kr) + par[kr] += 2*M_PI; + + } + + if (par[par.size()-1] - par[0] > 2*M_PI-closefac) + close = true; + } + + + double tmin = par[0]; + double tmax = par[par.size()-1]; + for (size_t ki=1; ki<par.size(); ++ki) + { + double dd = pts[ki-1].dist(pts[ki]); + par[ki] = par[ki-1] + dd; + } + + if (close) + { + size_t num = par.size(); + pts.push_back(pts[0]); // Repeat point at seam + par.push_back(par[num-1] + pts[num-1].dist(pts[num])); + } + + + BoundingBox ptbb(3); + for (size_t ki=0; ki<pts.size(); ++ki) + { + ptbb.addUnionWith(pts[ki]); + pts2.insert(pts2.end(), pts[ki].begin(), pts[ki].end()); + } + + + ApproxCurve approx(pts2, par, 3, tol, in, ik); + approx.setSmooth(smoothwgt); + + double maxspl, avspl; + shared_ptr<SplineCurve> cv = approx.getApproxCurve(maxspl, avspl, maxiter); + BoundingBox cvbb = cv->boundingBox(); +#ifdef DEBUG_ADJUST + cv->writeStandardHeader(of9); + cv->write(of9); +#endif + shared_ptr<ParamCurve> selcv = cv; + double maxlim = maxspl; + double avelem = avdist[pt_ix[0]]; + int inelem = num_inside[pt_ix[0]]; + double maxelem = maxdist[pt_ix[0]]; + if (pt_ix.size() > 1) + { + size_t num_pt = par.size(); + avelem = 0; + inelem = 0; + for (size_t kr=0; kr<pt_ix.size(); ++kr) + { + avelem += (double)all_points[pt_ix[kr]].size()*avdist[pt_ix[kr]]/ + (double)num_pt; + inelem += num_inside[pt_ix[kr]]; + maxelem = std::max(maxelem, maxdist[pt_ix[kr]]); + } + } + + double bbfac = 5.0; + if (avelem < avspl || (avelem <= tol && 2*inelem > (int)par.size()) || + cvbb.low().dist(cvbb.high()) > bbfac*ptbb.low().dist(ptbb.high())) + { + if (!close) + { + if (tmin < -2*M_PI) + { + tmin += 2*M_PI; + tmax += 2*M_PI; + } + if (tmax > 2*M_PI) + { + tmin -= 2*M_PI; + tmax -= 2*M_PI; + } + } + elemcv[kj]->setParamBounds(tmin, tmax); + selcv = elemcv[kj]; + maxlim = maxelem; + } + + // Check if the curve crosses a seam + vector<shared_ptr<ParamCurve> > subcvs; + splitAtSeam(surf, selcv, tol, angtol, maxlim, subcvs); + + vector<shared_ptr<CurveOnSurface> > trim_cv(subcvs.size()); + for (size_t kr=0; kr<subcvs.size(); ++kr) + { + shared_ptr<SplineCurve> proj_cv, par_cv; + CurveCreators::projectCurve(subcvs[kr], surf, tol, proj_cv, + par_cv); + trim_cv[kr] = shared_ptr<CurveOnSurface>(new CurveOnSurface(surf, proj_cv, + false)); + trim_cv[kr]->ensureParCrvExistence(tol); +#ifdef DEBUG_ADJUST + proj_cv->writeStandardHeader(of10); + proj_cv->write(of10); + shared_ptr<ParamCurve> tmp_par = trim_cv[kr]->parameterCurve(); + if (tmp_par.get()) + SplineDebugUtils::writeSpaceParamCurve(tmp_par, of11); +#endif + } + + for (size_t ki=0; ki<trim_cv.size(); ++ki) + { + double len = trim_cv[ki]->estimatedCurveLength(); + if (len < min_len) + continue; + shared_ptr<ftEdge> edg(new ftEdge(associated_sf_[0], trim_cv[ki], + trim_cv[ki]->startparam(), + trim_cv[ki]->endparam())); + addTrimEdge(edg); + } + int stop_spl = 1; + } + + + int stop_break2 = 1; +} + +//=========================================================================== +vector<RevEngPoint*> RevEngRegion::extractBdOutPoints(shared_ptr<SplineCurve>& crv, + vector<RevEngPoint*>& seq_pts, + double tol) +//=========================================================================== +{ + vector<RevEngPoint*> left, right, upper, lower; + vector<RevEngPoint*> points; + points.insert(points.end(), seq_pts.begin(), seq_pts.end()); + size_t seq_size = seq_pts.size(); + + for (size_t ki=0; ki<points.size(); ++ki) + points[ki]->setVisited(); + + double maxdist = 0.0; + for (size_t ki=0; ki<points.size(); ++ki) + { + if (ki == seq_size) + maxdist *= 2.0; + Vector3D xyz = points[ki]->getPoint(); + Point pos(xyz[0], xyz[1], xyz[2]); + double tpar, dist; + Point close; + crv->ParamCurve::closestPoint(pos, tpar, close, dist); + if (dist > maxdist) + { + if (ki < seq_size) + maxdist = dist; + else + continue; + } + + if (tpar <= crv->startparam()) + lower.push_back(points[ki]); + else if (tpar >= crv->endparam()) + upper.push_back(points[ki]); + else + { + vector<Point> der(2); + crv->point(der, tpar, 1); + Point norm = points[ki]->getLocFuncNormal(); + Point vec = pos - close; + Point vec2 = vec.cross(der[1]); + if (vec2*norm >= 0) + left.push_back(points[ki]); + else + right.push_back(points[ki]); + } + + vector<ftSamplePoint*> next = points[ki]->getNeighbours(); + for (size_t kj=0; kj<next.size(); ++kj) + { + RevEngPoint *curr = dynamic_cast<RevEngPoint*>(next[kj]); + RevEngRegion *adj_reg = curr->region(); + if (curr->visited()) + continue; + if (adj_reg != this) + continue; + curr->setVisited(); + points.push_back(curr); + } + } + + for (size_t ki=0; ki<points.size(); ++ki) + points[ki]->unsetVisited(); + + return (left.size() < right.size()) ? left : right; +} + +//=========================================================================== +vector<RevEngPoint*> RevEngRegion::sortPtsSeq(double mean_edge_len, + vector<RevEngPoint*>& seq_pts, + vector<RevEngPoint*>& sub_pts) +//=========================================================================== +{ + vector<RevEngPoint*> sub_pts2; + if (sub_pts.size() < 2) + { + // Check for maximum distance between input points + vector<RevEngPoint*> dummy; + if (seq_pts.size() < 2) + return dummy; + + double fac = 10.0; + size_t ix1 = 0, ix2 = 1; + ix2 = std::min(ix2, seq_pts.size()-1); + double maxlen = seq_pts[ix1]->pntDist(seq_pts[ix2]); + for (size_t ki=0; ki<seq_pts.size(); ++ki) + for (size_t kj=ki+1; kj<seq_pts.size(); ++kj) + { + double len = seq_pts[ki]->pntDist(seq_pts[kj]); + if (len > maxlen) + { + maxlen = len; + ix1 = ki; + ix2 = kj; + } + } + + if (sub_pts.size() == 1) + { + sub_pts2.push_back(sub_pts[0]); + double len1 = sub_pts[0]->pntDist(seq_pts[ix1]); + double len2 = sub_pts[0]->pntDist(seq_pts[ix2]); + if (len1 >= len2) + sub_pts2.push_back(seq_pts[ix1]); + else + sub_pts2.push_back(seq_pts[ix2]); + } + else + { + sub_pts2.push_back(seq_pts[ix1]); + if (maxlen > fac*mean_edge_len) + sub_pts2.push_back(seq_pts[ix2]); + } + } + else + sub_pts2.insert(sub_pts2.end(), sub_pts.begin(), sub_pts.end()); + vector<RevEngPoint*> seq_pts2(seq_pts.begin(), seq_pts.end()); + vector<vector<RevEngPoint*> > all_seq; + + while (sub_pts2.size() > 0) + { + size_t ix1 = 0, ix2 = 1; + ix2 = std::min(ix2, sub_pts2.size()-1); + double maxlen = sub_pts2[ix1]->pntDist(sub_pts2[ix2]); + for (size_t ki=0; ki<sub_pts2.size(); ++ki) + for (size_t kj=ki+1; kj<sub_pts2.size(); ++kj) + { + double len = sub_pts2[ki]->pntDist(sub_pts2[kj]); + if (len > maxlen) + { + maxlen = len; + ix1 = ki; + ix2 = kj; + } + } + + vector<RevEngPoint*> sortseq; + sortseq.push_back(sub_pts2[ix1]); + bool more_pts = true; + RevEngPoint *curr = sub_pts2[ix1]; + vector<RevEngPoint*> prev_pts; + while (more_pts) + { + vector<RevEngPoint*> next_pts; + vector<ftSamplePoint*> next = curr->getNeighbours(); + for (size_t ki=0; ki<next.size(); ++ki) + { + size_t kj; + for (kj=0; kj<next_pts.size(); ++kj) + if (next_pts[kj] == next[ki]) + break; + if (kj == next_pts.size()) + { + size_t kh; + for (kh=0; kh<sortseq.size(); ++kh) + if (sortseq[kh] == next[ki]) + break; + if (kh == sortseq.size()) + { + size_t kr; + for (kr=0; kr<seq_pts2.size(); ++kr) + if (seq_pts2[kr] == next[ki]) + break; + if (kr < seq_pts2.size()) + next_pts.push_back(dynamic_cast<RevEngPoint*>(next[ki])); + } + } + } + for (size_t ki=0; ki<next_pts.size(); ++ki) + for (size_t kj=ki+1; kj<next_pts.size(); ) + { + if (next_pts[ki] == next_pts[kj]) + next_pts.erase(next_pts.begin()+kj); + else + ++kj; + } + + if (next_pts.size() == 0) + next_pts = prev_pts; + + if (next_pts.size() == 0) + break; + if (next_pts.size() == 1) + { + prev_pts.clear(); + sortseq.push_back(next_pts[0]); + } + else + { + double minlen = curr->pntDist(next_pts[0]); + size_t ix3 = 0; + for (size_t kr=1; kr<next_pts.size(); ++kr) + { + double len = curr->pntDist(next_pts[kr]); + if (len < minlen) + { + minlen = len; + ix3 = kr; + } + } + prev_pts.clear(); + sortseq.push_back(next_pts[ix3]); + for (size_t kr=0; kr<next_pts.size(); ++kr) + if (kr != ix3) + prev_pts.push_back(next_pts[kr]); + } + curr = sortseq[sortseq.size()-1]; + } + +#ifdef DEBUG_SEGMENT + std::ofstream of("sorted_seq.g2"); + for (size_t ki=0; ki<sortseq.size(); ++ki) + { + of << "400 1 0 4 0 0 0 255" << std::endl; + of << "1" << std::endl; + of << sortseq[ki]->getPoint() << std::endl; + } +#endif + int stop_break = 1; + + for (size_t ki=0; ki<sortseq.size(); ++ki) + { + for (size_t kj=0; kj<sub_pts2.size(); ++kj) + { + if (sortseq[ki] == sub_pts2[kj]) + { + sub_pts2.erase(sub_pts2.begin()+kj); + break; + } + for (size_t kj=0; kj<seq_pts2.size(); ++kj) + { + if (sortseq[ki] == seq_pts2[kj]) + { + seq_pts2.erase(seq_pts2.begin()+kj); + break; + } + } + } + } + all_seq.push_back(sortseq); + } + + // Join sub sequences + vector<RevEngPoint*> sorted; + if (all_seq.size() > 0) + { + int all_size = (int)all_seq.size(); + while (all_size > 1) + { + double t1min = std::numeric_limits<double>::max(); + double t2min = std::numeric_limits<double>::max(); + int x1 = -1, x2 = -1; + bool turn1 = false, turn2 = false; + for (int kj=1; kj<all_size; ++kj) + { + double l1 = all_seq[0][0]->pntDist(all_seq[kj][0]); + double l2 = all_seq[0][0]->pntDist(all_seq[kj][all_seq[kj].size()-1]); + double l3 = all_seq[0][all_seq[0].size()-1]->pntDist(all_seq[kj][0]); + double l4 = all_seq[0][all_seq[0].size()-1]->pntDist(all_seq[kj][all_seq[kj].size()-1]); + if (std::min(l1, l2) < t1min) + { + t1min = std::min(l1, l2); + x1 = (int)kj; + turn1 = (l1 < l2); + } + + if (std::min(l3, l4) < t2min) + { + t2min = std::min(l3, l4); + x2 = (int)kj; + turn2 = (l4 < l3); + } + } + if (t1min < t2min) + { + if (turn1) + { + size_t last = all_seq[x1].size()-1; + for (size_t kr=0; kr<all_seq[x1].size()/2; ++kr) + std::swap(all_seq[x1][kr], all_seq[x1][last-kr]); + } + all_seq[0].insert(all_seq[0].begin(), all_seq[x1].begin(), + all_seq[x1].end()); + if (x1 < all_size-1) + std::swap(all_seq[x1],all_seq[all_size-1]); + } + else + { + if (turn2) + { + size_t last = all_seq[x2].size()-1; + for (size_t kr=0; kr<all_seq[x2].size()/2; ++kr) + std::swap(all_seq[x2][kr], all_seq[x2][last-kr]); + } + all_seq[0].insert(all_seq[0].end(), all_seq[x2].begin(), + all_seq[x2].end()); + if (x2 < all_size-1) + std::swap(all_seq[x2],all_seq[all_size-1]); + } + all_size--; + } + } + + bool include_missing = false; + if (include_missing) + { + // Include missing input points + for (size_t ki=0; ki<seq_pts2.size(); ++ki) + { + double minlen = seq_pts2[ki]->pntDist(all_seq[0][0]); + size_t min_ix = 0; + for (size_t kj=1; kj<all_seq[0].size(); ++kj) + { + double len = seq_pts2[ki]->pntDist(all_seq[0][kj]); + if (len < minlen) + { + min_ix = kj; + minlen = len; + } + } + + double len1 = (min_ix == 0) ? 0.0 : seq_pts2[ki]->pntDist(all_seq[0][min_ix-1]); + double len2 = (min_ix == all_seq[0].size()-1) ? 0.0 : + seq_pts2[ki]->pntDist(all_seq[0][min_ix+1]); + size_t ix = min_ix + (len2 > len1); + all_seq[0].insert(all_seq[0].begin()+ix, seq_pts2[ki]); + } + } + return all_seq[0]; +} + +//=========================================================================== +void RevEngRegion::adjustWithSurf(Point mainaxis[3], int min_pt_reg, + double tol, double angtol) +//=========================================================================== +{ + //double eps = 1.0e-6; + if (associated_sf_.size() == 0) + return; // No surface with which to check growt + + //int sfcode; + //ClassType classtype = associated_sf_[0]->instanceType(sfcode); + shared_ptr<ParamSurface> surf = associated_sf_[0]->surface(); + shared_ptr<BoundedSurface> bdsurf = + dynamic_pointer_cast<BoundedSurface,ParamSurface>(surf); + if (bdsurf.get()) + surf = bdsurf->underlyingSurface(); + +#ifdef DEBUG_ADJUST + std::ofstream res1("residuals_source.txt"); + for (size_t ki=0; ki<group_points_.size(); ++ki) + res1 << group_points_[ki]->getPoint() << " " << group_points_[ki]->getSurfaceDist() << std::endl; +#endif + + for (auto it=adjacent_regions_.begin(); it!=adjacent_regions_.end(); ++it) + { + // Check criteria for growt + //int num = (*it)->numPoints(); + // if (num > group_points_.size()) + // continue; + + std::ofstream res2("residuals_adj.txt"); + for (size_t kh=0; kh<(*it)->group_points_.size(); ++kh) + res2 << (*it)->group_points_[kh]->getPoint() << " " << (*it)->group_points_[kh]->getSurfaceDist() << std::endl; + +#ifdef DEBUG_SEGMENT + int num = (*it)->numPoints(); + std::ofstream of("curr_extend.g2"); + of << "400 1 0 4 0 255 0 255" << std::endl; + of << group_points_.size() << std::endl; + for (size_t kh=0; kh<group_points_.size(); ++kh) + of << group_points_[kh]->getPoint() << std::endl; + + of << "400 1 0 4 255 0 0 255" << std::endl; + of << num << std::endl; + for (int ka=0; ka<num; ++ka) + of << (*it)->getPoint(ka)->getPoint() << std::endl; + + surf->writeStandardHeader(of); + surf->write(of); +#endif + + vector<RevEngPoint*> in, out; + vector<pair<double, double> > dist_ang; + vector<double> parvals; + double maxd, avd; + int num_inside, num2_inside; + RevEngUtils::distToSurf((*it)->pointsBegin(), + (*it)->pointsEnd(), surf, tol, + maxd, avd, num_inside, num2_inside, in, out, + parvals, dist_ang); + vector<RevEngPoint*> better1, worse1; +#ifdef DEBUG_SEGMENT + std::ofstream res3("residuals_adj2.txt"); + for (size_t kh=0; kh<(*it)->group_points_.size(); ++kh) + res3 << (*it)->group_points_[kh]->getPoint() << " " << dist_ang[kh].first << std::endl; +#endif + + for (size_t kh=0; kh<dist_ang.size(); ++kh) + { + double ptdist = tol, ptang = angtol; + if ((*it)->hasSurface()) + (*it)->group_points_[kh]->getSurfaceDist(ptdist, ptang); + if (dist_ang[kh].first <= ptdist && dist_ang[kh].second < angtol) //ptang) + //if (dist_ang[kh].first <= tol) + better1.push_back((*it)->group_points_[kh]); + else + worse1.push_back((*it)->group_points_[kh]); + } +#ifdef DEBUG_SEGMENT + std::ofstream ofc1("better_worse1.g2"); + ofc1 << "400 1 0 4 155 50 50 255" << std::endl; + ofc1 << better1.size() << std::endl; + for (size_t kr=0; kr<better1.size(); ++kr) + ofc1 << better1[kr]->getPoint() << std::endl; + ofc1 << "400 1 0 4 50 155 50 255" << std::endl; + ofc1 << worse1.size() << std::endl; + for (size_t kr=0; kr<worse1.size(); ++kr) + ofc1 << worse1[kr]->getPoint() << std::endl; + + std::ofstream ofd("in_out_extend.g2"); + ofd << "400 1 0 4 155 50 50 255" << std::endl; + ofd << in.size() << std::endl; + for (size_t kr=0; kr<in.size(); ++kr) + ofd << in[kr]->getPoint() << std::endl; + ofd << "400 1 0 4 50 155 50 255" << std::endl; + ofd << out.size() << std::endl; + for (size_t kr=0; kr<out.size(); ++kr) + ofd << out[kr]->getPoint() << std::endl; +#endif + + vector<RevEngPoint*> better2, worse2; + if ((*it)->hasSurface()) + { + shared_ptr<ParamSurface> surf2 = (*it)->getSurface(0)->surface(); + double maxd2, avd2; + int num_inside2, num2_inside2; + vector<RevEngPoint*> in2, out2; + vector<pair<double, double> > dist_ang2; + vector<double> parvals2; + RevEngUtils::distToSurf(pointsBegin(), + pointsEnd(), surf2, tol, + maxd2, avd2, num_inside2, num2_inside2, in2, out2, + parvals2, dist_ang2); + for (size_t kh=0; kh<dist_ang2.size(); ++kh) + { + double ptdist, ptang; + group_points_[kh]->getSurfaceDist(ptdist, ptang); + if (dist_ang2[kh].first <= ptdist && dist_ang2[kh].second < angtol) //ptang) + { + better2.push_back(group_points_[kh]); + } + else + worse2.push_back(group_points_[kh]); + } +#ifdef DEBUG_SEGMENt + std::ofstream ofc2("better_worse2.g2"); + ofc2 << "400 1 0 4 155 50 50 255" << std::endl; + ofc2 << better2.size() << std::endl; + for (size_t kr=0; kr<better2.size(); ++kr) + ofc2 << better2[kr]->getPoint() << std::endl; + ofc2 << "400 1 0 4 50 155 50 255" << std::endl; + ofc2 << worse2.size() << std::endl; + for (size_t kr=0; kr<worse2.size(); ++kr) + ofc2 << worse2[kr]->getPoint() << std::endl; +#endif + } + + // Move points + bool move2 = false; + size_t b1size = 2*better1.size(); + while (better1.size() < b1size) + { + b1size = better1.size(); + for (size_t ki=0; ki<better1.size(); ) + { + if (better1[ki]->isNeighbour(this)) + { + move2 = true; + (*it)->removePoint(better1[ki]); + better1[ki]->setRegion(this); + better1[ki]->addMove(); + group_points_.push_back(better1[ki]); + better1.erase(better1.begin()+ki); + } + else + ++ki; + } + } + + if (false) + { + size_t b2size = 2*better2.size(); + while (better2.size() < b2size) + { + b2size = better2.size(); + for (size_t ki=0; ki<better2.size(); ) + { + if (better2[ki]->isNeighbour(*it)) + { + move2 = true; + removePoint(better2[ki]); + better2[ki]->setRegion(*it); + better2[ki]->addMove(); + (*it)->addPoint(better2[ki]); + better2.erase(better2.begin()+ki); + } + else + ++ki; + } + } + } + + if ((*it)->hasSurface() && (*it)->numPoints() > 5 && move2) + { + // Check if the surface should be updated + (*it)->checkReplaceSurf(mainaxis, min_pt_reg, tol, angtol); + } + } + + + // Check if the surface should be updated + checkReplaceSurf(mainaxis, min_pt_reg, tol, angtol); +#ifdef DEBUG_SEGMENt + std::ofstream res4("residuals_res.txt"); + for (size_t ki=0; ki<group_points_.size(); ++ki) + res4 << group_points_[ki]->getPoint() << " " << group_points_[ki]->getSurfaceDist() << std::endl; +#endif + int stop_break = 1; + +} + +//=========================================================================== +bool RevEngRegion::getCurveRestriction(vector<shared_ptr<CurveOnSurface> >& cvs, + double tol, double anglim, + vector<pair<double,double> >& endpars) +//=========================================================================== +{ + double int_tol = 1.0e-6; + Point corner[4]; + corner[0] = Point(domain_[0], domain_[2]); + corner[1] = Point(domain_[1], domain_[2]); + corner[2] = Point(domain_[0], domain_[3]); + corner[3] = Point(domain_[1], domain_[3]); + + // Ensure parameter representation of curves + endpars.resize(cvs.size()); + for (size_t ki=0; ki<cvs.size(); ++ki) + { + double start = std::numeric_limits<double>::max(); + double end = std::numeric_limits<double>::lowest(); + if (!(cvs[ki]->hasParameterCurve())) + { + shared_ptr<ParamSurface> surf = cvs[ki]->underlyingSurface(); + if (!surf->isBounded()) + { + double diag = bbox_.low().dist(bbox_.high()); + associated_sf_[0]->limitSurf(2*diag); + } + bool OK = cvs[ki]->ensureParCrvExistence(tol); + if (!OK) + { + // Curve larger than surface. Get initial restriction + shared_ptr<ParamSurface> surf = cvs[ki]->underlyingSurface(); + CurveLoop cvloop = surf->outerBoundaryLoop(); + vector<shared_ptr<ParamCurve> > lcvs = cvloop.getCurves(); + shared_ptr<ParamCurve> scurve = cvs[ki]->spaceCurve(); + vector<double> parvals; + for (size_t kr=0; kr<lcvs.size(); ++kr) + { + vector<pair<double,double> > intpts; + intersectParamCurves(scurve.get(), lcvs[kr].get(), int_tol, + intpts); + for (size_t kj=0; kj<intpts.size(); ++kj) + parvals.push_back(intpts[kj].first); + } + std::sort(parvals.begin(), parvals.end()); + double t1 = cvs[ki]->startparam(); + double t2 = cvs[ki]->endparam(); + if (parvals.size() > 1) + { + t1 = parvals[0]; + t2 = parvals[parvals.size()-1]; + } + else if (parvals.size() == 1) + { + Point pt1 = scurve->point(t1); + Point pt2 = scurve->point(t2); + double u1, u2, v1, v2, d1, d2; + Point cl1, cl2; + surf->closestPoint(pt1, u1, v1, cl1, d1, int_tol); + surf->closestPoint(pt2, u2, v2, cl2, d2, int_tol); + if (d1 <= d2) + t2 = parvals[0]; + else + t1 = parvals[0]; + } + shared_ptr<CurveOnSurface> sub_cv(cvs[ki]->subCurve(t1,t2)); + cvs[ki] = sub_cv; + OK = cvs[ki]->ensureParCrvExistence(tol); + if (!OK) + continue; + } + } + + start = std::min(start, cvs[ki]->startparam()); + end = std::max(end, cvs[ki]->endparam()); + endpars[ki] = std::make_pair(start,end); + } + + // Special treatment of closed curve + double seam_dist = std::numeric_limits<double>::max(); + if (cvs.size() == 1) + { + Point startpt = cvs[0]->ParamCurve::point(cvs[0]->startparam()); + Point endpt = cvs[0]->ParamCurve::point(cvs[0]->endparam()); + if (startpt.dist(endpt) <= tol) + { + closestPoint(startpt, seam_dist); + } + } + + // Restrict curve with respect to parameter domain + double fac = 0.1; + for (size_t ki=0; ki<cvs.size(); ++ki) + { + vector<double> cvparam(4); + shared_ptr<ParamCurve> pcurve = cvs[ki]->parameterCurve(); + if (!pcurve.get()) + continue; + BoundingBox bbp = pcurve->boundingBox(); + double u1 = bbp.low()[0]; + double u2 = bbp.high()[0]; + double v1 = bbp.low()[1]; + double v2 = bbp.high()[1]; + double udel = fac*(domain_[1] - domain_[0]); + double vdel = fac*(domain_[3] - domain_[2]); + bool inside = true; + for (int ka=0; ka<4; ++ka) + { + double dist; + Point close; + pcurve->closestPoint(corner[ka], pcurve->startparam(), + pcurve->endparam(), cvparam[ka], close, dist); + if (dist < seam_dist && (u1 < domain_[0]-udel || u2 > domain_[1]+udel || + v1 < domain_[2]-vdel || v2 > domain_[3]+vdel)) + inside = false; + } + std::sort(cvparam.begin(), cvparam.end()); + if (inside) + { + endpars[ki].first = pcurve->startparam(); + endpars[ki].second = pcurve->endparam(); + } + else + { + endpars[ki].first = cvparam[0]; + endpars[ki].second = cvparam[3]; + } + } + + + return true; +} + +//=========================================================================== +void RevEngRegion::checkReplaceSurf(Point mainaxis[3], int min_pt_reg, + double tol, double angtol, bool always) +//=========================================================================== +{ + int sfcode; + ClassType classtype[2]; + classtype[0] = Class_Unknown; + classtype[1] = associated_sf_[0]->instanceType(sfcode); + shared_ptr<ParamSurface> primary; + if (basesf_.get() && avdist_base_ < tol && + num_in_base_ > (int)group_points_.size()/2) + { + primary = basesf_; + classtype[0] = primary->instanceType(); + } + + shared_ptr<SplineCurve> profile; + Point pt1, pt2; + bool cyllike = false; + for (int ka=0; ka<2; ++ka) + { + if (classtype[ka] == Class_Unknown) + continue; + + shared_ptr<ParamSurface> updated, updated2; + if (classtype[ka] == Class_SplineSurface && sfcode == 1) + updated = computeLinearSwept(tol, profile, pt1, pt2); + else + computeSurface(group_points_, mainaxis, tol, angtol, classtype[ka], + updated, updated2, cyllike); + + shared_ptr<ParamSurface> replacesurf; + if (updated.get()) + { + double maxd, avd; + int num_inside, num2_inside; + vector<RevEngPoint*> inpt, outpt; + vector<pair<double, double> > dist_ang; + vector<double> parvals; + RevEngUtils::distToSurf(group_points_.begin(), group_points_.end(), + updated, tol, maxd, avd, num_inside, num2_inside, + inpt, outpt, parvals, dist_ang, angtol); + int sf_flag1 = defineSfFlag(0, tol, num_inside, num2_inside, avd, + cyllike); + if (updated2.get()) + { + double maxd2, avd2; + int num_inside2, num2_inside2; + vector<RevEngPoint*> inpt2, outpt2; + vector<pair<double, double> > dist_ang2; + vector<double> parvals2; + RevEngUtils::distToSurf(group_points_.begin(), group_points_.end(), + updated2, tol, maxd2, avd2, num_inside2, + num2_inside2, inpt2, outpt2, parvals2, + dist_ang2, angtol); + int sf_flag2 = defineSfFlag(0, tol, num_inside2, num2_inside2, avd2, + cyllike); + if ((sf_flag2 < sf_flag1 || + (num_inside2 > num_inside || + (num_inside2 == num_inside && avd2 < avd))) && + (sf_flag2 < surfflag_ || + (((num_inside2 > num_inside_ || + (num_inside2 == num_inside_ && avd2 < avdist_)) + && avd2 < tol)) || always)) + { + replacesurf = updated2; + for (size_t kh=0; kh<group_points_.size(); ++kh) + { + group_points_[kh]->setPar(Vector2D(parvals2[2*kh],parvals2[2*kh+1])); + group_points_[kh]->setSurfaceDist(dist_ang2[kh].first, dist_ang2[kh].second); + } + setAccuracy(maxd2, avd2, num_inside2, num2_inside2); + setSurfaceFlag(sf_flag2); + } + if (ka == 0 && num_inside2 >= num_in_base_ && avd2 < avdist_base_) + { + setBaseSf(updated2, maxd2, avd2, num_inside2, num2_inside2); + } + int stop_break2 = 1; + } + if ((!replacesurf.get()) && + (sf_flag1 < surfflag_ || + (num_inside > num_inside_ || + (num_inside == num_inside_ && avd < avdist_)) || always)) + { + replacesurf = updated; + for (size_t kh=0; kh<group_points_.size(); ++kh) + { + group_points_[kh]->setPar(Vector2D(parvals[2*kh],parvals[2*kh+1])); + group_points_[kh]->setSurfaceDist(dist_ang[kh].first, dist_ang[kh].second); + } + setAccuracy(maxd, avd, num_inside, num2_inside); + setSurfaceFlag(sf_flag1); + } + if (ka == 0 && num_inside >= num_in_base_ && avd < avdist_base_) + { + setBaseSf(updated, maxd, avd, num_inside, num2_inside); + } + int stop_break = 1; + } + + if (replacesurf.get()) + { + associated_sf_[0]->replaceSurf(replacesurf); + if (!replacesurf->isBounded()) + { + double diag = bbox_.low().dist(bbox_.high()); + associated_sf_[0]->limitSurf(2*diag); + } + + surf_adaption_ = INITIAL; + if (sfcode == 1 && profile.get()) + { + // A linear swept surface + associated_sf_[0]->setLinearSweepInfo(profile, pt1, pt2); + } + computeDomain(); + for (size_t kj=0; kj<rev_edges_.size(); ++kj) + rev_edges_[kj]->replaceSurf(this, replacesurf, tol); + } + } +} + + +//=========================================================================== +int RevEngRegion::checkSurfaceAccuracy(vector<shared_ptr<ElementarySurface> >& sfs, + double tol, double angtol, double& maxd, + double& avd, int& num_in, + int& num2_in, int& sf_flag) +//=========================================================================== +{ + vector<double> maxdist(sfs.size()); + vector<double> avdist(sfs.size()); + vector<int> num_inside(sfs.size()); + vector<int> num2_inside(sfs.size()); + vector<int> surf_flag(sfs.size()); + + for (size_t ki=0; ki<sfs.size(); ++ki) + { + bool cyllike = (sfs[ki]->instanceType() == Class_Cylinder || + sfs[ki]->instanceType() == Class_Cone); + vector<RevEngPoint*> inpt, outpt; + vector<pair<double, double> > dist_ang; + vector<double> parvals; + RevEngUtils::distToSurf(group_points_.begin(), group_points_.end(), + sfs[ki], tol, maxdist[ki], avdist[ki], + num_inside[ki], num2_inside[ki], + inpt, outpt, parvals, dist_ang, angtol); + surf_flag[ki] = defineSfFlag(0, tol, num_inside[ki], num2_inside[ki], + avdist[ki], cyllike); + } + + int ix = 0; + double fac = 1.2; + for (size_t ki=1; ki<sfs.size(); ++ki) + { + if (surf_flag[ki] < surf_flag[ix] || + (surf_flag[ki] == surf_flag[ix] && + ((num2_inside[ki] >= num2_inside[ix] && avdist[ki] <= avdist[ix]) || + (double)num2_inside[ki] >= fac*(double)num2_inside[ix] || + fac*avdist[ki] <= avdist[ix]))) + ix = (int)ki; + } + maxd = maxdist[ix]; + avd = avdist[ix]; + num_in = num_inside[ix]; + num2_in = num2_inside[ix]; + sf_flag = surf_flag[ix]; + + return (sf_flag < NOT_SET) ? ix : -1; +} + +//=========================================================================== +void RevEngRegion::parameterizePoints(double tol, double angtol) +//=========================================================================== +{ + if (!hasSurface()) + return; + + shared_ptr<ParamSurface> surf = getSurface(0)->surface(); + + // Compute accuracy + vector<RevEngPoint*> inpt, outpt; + vector<pair<double, double> > dist_ang; + double maxd, avd; + int num_in, num2_in; + vector<double> parvals; + RevEngUtils::distToSurf(group_points_.begin(), group_points_.end(), + surf, tol, maxd, avd, num_in, num2_in, + inpt, outpt, parvals, dist_ang, + angtol); + + // Update info in points + for (size_t kh=0; kh<group_points_.size(); ++kh) + { + group_points_[kh]->setPar(Vector2D(parvals[2*kh],parvals[2*kh+1])); + group_points_[kh]->setSurfaceDist(dist_ang[kh].first, dist_ang[kh].second); + } + + updateInfo(tol, angtol); + + bool cyllike = (surf->instanceType() == Class_Cylinder || + surf->instanceType() == Class_Cone); + int sf_flag = defineSfFlag(0, tol, num_inside_, num_inside2_, + avdist_, cyllike); + setSurfaceFlag(sf_flag); +} + +//=========================================================================== +bool RevEngRegion::isCompatible(ClassType classtype, int sfcode) +//=========================================================================== +{ + return true; + double anglim = 0.1; + if (classtype == Class_Plane) + { + if (planartype() || (normalcone_.angle() <= anglim && + (!normalcone_.greaterThanPi()))) + return true; + else + return false; + } + else + if (classtype == Class_Cylinder) + { + return true; // Must mike proper criteria + } + return false; // To be extended +} + + +//=========================================================================== +void RevEngRegion::computeSurface(vector<RevEngPoint*>& points, + Point mainaxis[3], double tol, + double angtol, ClassType classtype, + shared_ptr<ParamSurface>& updated, + shared_ptr<ParamSurface>& updated2, + bool& cyllike) +//=========================================================================== +{ + if (classtype == Class_Plane) + { + updated = computePlane(points, avnorm_, mainaxis); + } + else if (classtype == Class_Cylinder) + { + cyllike = true; + updated = computeCylinder(points, tol); + } + else if (classtype == Class_Sphere) + { + Point axis; + if (hasSurface()) + { + shared_ptr<ElementarySurface> elem = + dynamic_pointer_cast<ElementarySurface,ParamSurface>(associated_sf_[0]->surface()); + if (elem.get()) + axis = elem->direction(); + } + updated = computeSphere(mainaxis, axis, points); + } + else if (classtype == Class_Cone) + { + cyllike = true; + Point apex; + updated = computeCone(points, apex); + } + else if (classtype == Class_Torus) + { + //shared_ptr<Torus> torus2; + vector<Point> dummy_axis; + updated = computeTorus(points, dummy_axis, tol, angtol); + //updated2 = torus2; + } + else if (classtype == Class_SplineSurface) + { + updated = updateFreeform(points, tol); + if (!updated.get()) + updated = computeFreeform(points, tol); + } +#ifdef DEBUG_UPDATE + if (updated.get()) + { + std::ofstream ofn("updated.g2"); + updated->writeStandardHeader(ofn); + updated->write(ofn); + if (updated2.get()) + { + updated2->writeStandardHeader(ofn); + updated2->write(ofn); + } + } +#endif +} + + +//=========================================================================== +void RevEngRegion::splitCylinderRad(const Point& pos, const Point& axis, + const Point& Cx, const Point& Cy, + int nmb_split, vector<Point>& centr, + vector<double>& rad) +//=========================================================================== +{ + centr.resize(nmb_split); + rad.resize(nmb_split); + shared_ptr<Line> line(new Line(pos, axis)); + vector<double> par(group_points_.size()); + double tmin = std::numeric_limits<double>::max(); + double tmax = std::numeric_limits<double>::lowest(); + double diag = bbox_.low().dist(bbox_.high()); + double tmin0 = -diag; + double tmax0 = diag; + for (size_t ki=0; ki<group_points_.size(); ++ki) + { + Vector3D xyz = group_points_[ki]->getPoint(); + Point curr(xyz[0], xyz[1], xyz[2]); + double tpar, dist; + Point close; + line->closestPoint(curr, tmin0, tmax0, tpar, close, dist); + par[ki] = tpar; + tmin = std::min(tmin, tpar); + tmax = std::max(tmax, tpar); + } + + double tdel = (tmax - tmin)/(double)nmb_split; + vector<Point> mid(nmb_split); + double tpar = tmin + 0.5*tdel; + for (int ka=0; ka<nmb_split; ++ka, tpar+=tdel) + mid[ka] = line->ParamCurve::point(tpar); + + vector<vector<Point> > proj_pts(nmb_split); + for (size_t ki=0; ki<group_points_.size(); ++ki) + { + Vector3D pnt = group_points_[ki]->getPoint(); + size_t kj; + for (kj=0, tpar=tmin; kj<mid.size(); ++kj, tpar+=tdel) + if (par[ki] >= tpar && par[ki] < tpar+tdel) + break; + kj = std::min(kj, mid.size()-1); + Point curr(pnt[0], pnt[1], pnt[2]); + Point curr2 = curr - mid[kj]; + curr2 -= ((curr2*axis)*axis); + curr2 += mid[kj]; + proj_pts[kj].push_back(curr2); + } + +#ifdef DEBUG_SEGMENT + std::ofstream of("split_circ.g2"); + for (size_t kj=0; kj<proj_pts.size(); ++kj) + { + RevEngUtils::computeCircPosRadius(proj_pts[kj], axis, Cx, Cy, centr[kj], rad[kj]); + shared_ptr<Circle> circ(new Circle(rad[kj], centr[kj], axis, Cx)); + circ->writeStandardHeader(of); + circ->write(of); + of << "400 1 0 4 255 0 0 255" << std::endl; + of << proj_pts[kj].size() << std::endl; + for (size_t kr=0; kr<proj_pts[kj].size(); ++kr) + of << proj_pts[kj][kr] << std::endl; + } +#endif + + + int stop_break = 1; + } + + +int compare_t(const void* el1, const void* el2) +{ + if (((double*)el1)[0] < ((double*)el2)[0]) + return -1; + else if (((double*)el1)[0] > ((double*)el2)[0]) + return 1; + else + return 0; +} + +//=========================================================================== +void RevEngRegion::curveApprox(vector<Point>& points, double tol, + shared_ptr<Circle> circle, vector<double>& parval, + shared_ptr<SplineCurve>& curve, Point& xpos) +//=========================================================================== +{ + double eps = 0.001; + vector<double> pts; + vector<double> param; + double tmin = circle->startparam(); + double tmax = circle->endparam(); + double tdel = tmax - tmin; + double tmin2 = tmax; + double tmax2 = tmin; + vector<double> tmppts; + tmppts.reserve(4*points.size()); + parval.resize(points.size()); + for (size_t ki=0; ki<points.size(); ++ki) + { + double tpar, dist; + Point close; + circle->closestPoint(points[ki], tmin, tmax, tpar, close, dist); + // if (ki > 0 && ((tpar-tmin < tmin2-tpar && tmax-tmax2 < tmin2-tmin) || + // (tmax-tpar < tpar-tmax2 && tmin2-tmin < tmax-tmax2))) + if (ki > 0 && (tpar<tmin2 || tpar>tmax2) && + std::min(fabs(tmin2-tpar+tdel),fabs(tpar+tdel-tmax2)) < + std::min(fabs(tpar-tmax2),fabs(tpar-tmin2))) + //(fabs(tmin2-tpar+tdel) < fabs(tpar-tmax2) || fabs(tpar+tdel-tmax2) < fabs(tpar-tmax2))) + { + if (tpar-tmin < tmax-tpar) + tpar += tdel; + else + tpar -= tdel; + } + + parval[ki] = tpar; + tmppts.push_back(tpar); + tmppts.insert(tmppts.end(), points[ki].begin(), points[ki].end()); + // pts.insert(pts.end(), points[ki].begin(), points[ki].end()); + // param.push_back(tpar); + tmin2 = std::min(tmin2, tpar); + tmax2 = std::max(tmax2, tpar); + } + + qsort(&tmppts[0], points.size(), 4*sizeof(double), compare_t); + pts.resize(3*points.size()); + param.resize(points.size()); + for (size_t ki=0; ki<points.size(); ++ki) + { + param[ki] = tmppts[4*ki]; + for (size_t ka=0; ka<3; ++ka) + pts[3*ki+ka] = tmppts[4*ki+ka+1]; + } + + if (tmax2 - tmin2 < 2*M_PI-eps && (tmin2 < -eps || tmax2 > 2*M_PI+eps)) + { + double tpar = (tmax2 > 2*M_PI+eps) ? 0.5*(tmax2 + tmin2 - 2*M_PI) + : 0.5*(tmin2 + tmax2 + 2*M_PI); + xpos = circle->ParamCurve::point(tpar); + } + + int inner = (int)(2.0*(tmax2 - tmin2)/M_PI); + int ik = 4; + int in = ik + inner; + // double tdel = (tmax2 - tmin2)/(double)(in - ik + 1); + // double et[12]; + // for (int ka=0; ka<ik; ++ka) + // { + // et[ka] = tmin2; + // et[in+ka] = tmax2; + // } + // for (int ka=ik; ka<in; ++ka) + // et[ka] = tmin2 + (ka-ik+1)*tdel; + + double smoothwgt = 1.0e-9; //0.001; + ApproxCurve approx(pts, param, 3, tol, in, ik); + approx.setSmooth(smoothwgt); + int maxiter = 4; //3; + double maxdist, avdist; + curve = approx.getApproxCurve(maxdist, avdist, maxiter); + // vector<double> ecoef(3*in, 0.0); + // shared_ptr<SplineCurve> cv(new SplineCurve(in, ik, et, &ecoef[0], 3)); + + // SmoothCurve smooth(3); + // vector<int> cfn(in, 0); + // vector<double> wgts(param.size(), 1.0); + // smooth.attach(cv, &cfn[0]); + + // double wgt1 = 0.0, wgt2 = 0.1, wgt3 = 0.1; + // double approxwgt = 1.0 - wgt1 - wgt2 - wgt3; + // smooth.setOptim(wgt1, wgt2, wgt3); + // smooth.setLeastSquares(pts, param, wgts, approxwgt); + + // shared_ptr<SplineCurve> curve0; + // smooth.equationSolve(curve0); +#ifdef DEBUG + std::ofstream of("points_and_tangents.txt"); + of << points.size() << std::endl; + for (size_t ki=0; ki<points.size(); ++ki) + { + of << pts[3*ki] << " " << pts[3*ki+1] << " "; + vector<Point> der(2); + curve->point(der, param[ki], 1); + of << der[1][0] << " " << der[1][1] << std::endl; + } +#endif + int stop_break = 1; +} + +//=========================================================================== +void RevEngRegion::configSplit(vector<RevEngPoint*>& points, + vector<double>& param, + shared_ptr<Cylinder> cyl, + shared_ptr<SplineCurve> spl, double tol, + vector<vector<RevEngPoint*> >& configs) +//=========================================================================== +{ + // Check cylinder axis + Point axis = cyl->direction(); + double angtol = 0.2; + double inlim = 0.8; + int nmb_in = 0; + double mpi2 = 0.5*M_PI; + vector<Vector3D> low, high; + for (size_t kr=0; kr<group_points_.size(); ++kr) + { + Point normal = group_points_[kr]->getLocFuncNormal(); + double ang = axis.angle(normal); + if (ang < mpi2) + low.push_back(group_points_[kr]->getPoint()); + else + high.push_back(group_points_[kr]->getPoint()); + if (fabs(ang-mpi2) <= angtol) + nmb_in++; + } + double in_frac = (double)nmb_in/(double)group_points_.size(); + if (in_frac < inlim) + return; + +#ifdef DEBUG_SEGMENT + std::ofstream of1("low_axis.g2"); + of1 << "400 1 0 4 100 155 0 255" << std::endl; + of1 << low.size() << std::endl; + for (size_t kr=0; kr<low.size(); ++kr) + of1 << low[kr] << std::endl; + + std::ofstream of2("high_axis.g2"); + of2 << "400 1 0 4 0 155 100 255" << std::endl; + of2 << high.size() << std::endl; + for (size_t kr=0; kr<high.size(); ++kr) + of2 << high[kr] << std::endl; +#endif + + // Compute all intersections between the cylinder and the spline curve + double eps = std::min(1.0e-6, 0.1*tol); + vector<double> intpar; + vector<pair<double,double> > int_cvs; + intersectCurveCylinder(spl.get(), cyl->getLocation(), cyl->getAxis(), + cyl->getRadius(), eps, intpar, int_cvs); + for (size_t ki=0; ki<int_cvs.size(); ++ki) + { + intpar.push_back(int_cvs[ki].first); + intpar.push_back(int_cvs[ki].second); + } + if (intpar.size() == 0) + return; + + // Define parameter intervals of different configurations + std::sort(intpar.begin(), intpar.end()); + vector<double> delpar; + + // Check startpoint, endpoint and points in the middle of intervals + double upar, vpar, dist; + Point close; + Point pos = spl->ParamCurve::point(spl->startparam()); + cyl->closestPoint(pos, upar, vpar, close, dist, eps); + delpar.push_back(spl->startparam()-tol); + if (dist > tol) + { + delpar.push_back(intpar[0]); + } + for (size_t ki=1; ki<intpar.size(); ++ki) + { + double tpar = 0.5*(intpar[ki-1] + intpar[ki]); + pos = spl->ParamCurve::point(tpar); + cyl->closestPoint(pos, upar, vpar, close, dist, eps); + if (dist > tol) + delpar.push_back(intpar[ki]); + } + pos = spl->ParamCurve::point(spl->endparam()); + cyl->closestPoint(pos, upar, vpar, close, dist, eps); + if (dist > tol) + { + if (delpar.size() > 0 && + intpar[intpar.size()-1] > delpar[delpar.size()-1]) + delpar.push_back(intpar[intpar.size()-1]); + } + delpar.push_back(spl->endparam()); + + if (delpar.size() == 0) + return; + + // Divide point set according to configuration + configs.resize(delpar.size()-1); + for (size_t kj=0; kj<points.size(); ++kj) + { + for (size_t ki=1; ki<delpar.size(); ++ki) + if (param[kj] > delpar[ki-1] && param[kj] <= delpar[ki]) + { + configs[ki-1].push_back(points[kj]); + break; + } + } + int stop_break = 1; +} + +//=========================================================================== +bool RevEngRegion::hasEdgeBetween(RevEngRegion* adj) +//=========================================================================== +{ + if (adj->numPoints() < (int)group_points_.size()) + return adj->hasEdgeBetween(this); + + for (size_t ki=0; ki<group_points_.size(); ++ki) + { + vector<ftSamplePoint*> next = group_points_[ki]->getNeighbours(); + for (size_t kj=0; kj<next.size(); ++kj) + { + RevEngPoint *pt = dynamic_cast<RevEngPoint*>(next[kj]); + if (!pt->isEdge(edge_class_type_)) + continue; + + vector<ftSamplePoint*> next2 = pt->getNeighbours(); + for (size_t kr=0; kr<next2.size(); ++kr) + { + RevEngPoint *pt2 = dynamic_cast<RevEngPoint*>(next2[kr]); + if (pt2->region() == adj) + return true; + } + } + } + return false; +} + +//=========================================================================== +void RevEngRegion::store(std::ostream& os) const +//=========================================================================== +{ + os << Id_ << std::endl; + os << group_points_.size() << std::endl; +for (size_t ki=0; ki<group_points_.size(); ++ki) + os << group_points_[ki]->getIndex() << " "; + os << std::endl; + os << classification_type_ << " " << surfflag_ << " " << surf_adaption_; + os << " " << frac_norm_in_ << " " << frac_norm_in2_ << std::endl; + os << maxdist_ << " " << avdist_ << " " << num_inside_; + os << " " << num_inside2_ << " " << std::endl; + int base = basesf_.get() ? 1 : 0; + os << base << std::endl; + if (base) + { + basesf_->writeStandardHeader(os); + basesf_->write(os); + os << maxdist_base_ << " " << avdist_base_ << " " << num_in_base_; + os << " " << num_in_base2_ << std::endl; + } + + os << associated_sf_.size() << std::endl; + for (size_t ki=0; ki<associated_sf_.size(); ++ki) + os << associated_sf_[ki]->getId() << " "; + + int sweep = sweep_.get() ? 1 : 0; + os << sweep << std::endl; + if (sweep_) + { + os << sweep_->type_ << std::endl; + if (sweep_->profile_.get()) + { + os << "1" << std::endl; + sweep_->profile_->writeStandardHeader(os); + sweep_->profile_->write(os); + } + else + os << "0" << std::endl; + os << sweep_->location_ << " " << sweep_->added_info_ << " "; + os << sweep_->radius_ << " " << sweep_->angle_ << std::endl; + os << sweep_->maxdist_ << " " << sweep_->avdist_ << " " << sweep_->num_in_<< std::endl; + } +} + +//=========================================================================== +void RevEngRegion::read(std::istream& is, + shared_ptr<ftPointSet>& tri_sf, + vector<int>& associated_sf_id) +//=========================================================================== +{ + GoTools::init(); + is >> Id_; + int num_points; + is >> num_points; + group_points_.resize(num_points); + int ix; + for (int ki=0; ki<num_points; ++ki) + { + is >> ix; + RevEngPoint* pt = dynamic_cast<RevEngPoint*>((*tri_sf)[ix]); + pt->setRegion(this); + group_points_[ki] = pt; + } + is >> classification_type_ >> surfflag_ >> surf_adaption_; + is >> frac_norm_in_ >> frac_norm_in2_; + is >> maxdist_ >> avdist_ >> num_inside_ >> num_inside2_; + int base; + is >> base; + + if (base) + { + ObjectHeader header; + header.read(is); + shared_ptr<GeomObject> obj(Factory::createObject(header.classType())); + obj->read(is); + basesf_ = dynamic_pointer_cast<ParamSurface,GeomObject>(obj); + is >> maxdist_base_ >> avdist_base_ >> num_in_base_ >> num_in_base2_; + } + + int num_sf; + is >> num_sf; + for (int ki=0; ki<num_sf; ++ki) + { + int sf_id; + is >> sf_id; + associated_sf_id.push_back(sf_id); + } + if (num_sf > 0) + computeDomain(); + + int sweep; + is >> sweep; + if (sweep) + { + int stype, snum_in, sprof; + double rad, ang, maxd, avd; + Point loc(3), added(3); + shared_ptr<SplineCurve> profile; + is >> stype; + is >> sprof; + if (sprof) + { + ObjectHeader header; + header.read(is); + profile = shared_ptr<SplineCurve>(new SplineCurve()); + profile->read(is); + } + is >> loc >> added >> rad >> ang >> maxd >> avd >> snum_in; + sweep_ = shared_ptr<SweepData>(new SweepData(stype, profile, loc, added, maxd, + avd, snum_in, rad, ang)); + } + + // Bounding box and principal curvature summary + maxk2_ = std::numeric_limits<double>::lowest(); + mink2_ = std::numeric_limits<double>::max(); + maxk1_ = std::numeric_limits<double>::lowest(); + mink1_ = std::numeric_limits<double>::max(); + MAH_ = MAK_ = avH_ = avK_ = 0.0; + bbox_ = BoundingBox(3); + if (group_points_.size() > 0) + { + double fac = 1.0/(double)group_points_.size(); + for (size_t kj=0; kj<group_points_.size(); ++kj) + { + double k1 = group_points_[kj]->minPrincipalCurvature(); + double k2 = group_points_[kj]->maxPrincipalCurvature(); + double H = group_points_[kj]->meanCurvature(); + double K = group_points_[kj]->GaussCurvature(); + mink1_ = std::min(mink1_, fabs(k1)); + maxk1_ = std::max(maxk1_, fabs(k1)); + mink2_ = std::min(mink2_, fabs(k2)); + maxk2_ = std::max(maxk2_, fabs(k2)); + avH_ += fac*H; + avK_ += fac*K; + MAH_ += fac*fabs(H); + MAK_ += fac*fabs(K); + Vector3D point = group_points_[kj]->getPoint(); + Point point2(point[0], point[1], point[2]); + bbox_.addUnionWith(point2); + } + + normalcone_ = DirectionCone(group_points_[0]->getLocFuncNormal()); + normalcone2_ = DirectionCone(group_points_[0]->getTriangNormal()); + avnorm_ = Point(0.0, 0.0, 0.0); + avnorm2_ = Point(0.0, 0.0, 0.0); + for (size_t kj=1; kj<group_points_.size(); ++kj) + { + Point norm = group_points_[kj]->getLocFuncNormal(); + normalcone_.addUnionWith(norm); + avnorm_ += fac*norm; + Point norm2 = group_points_[kj]->getTriangNormal(); + normalcone2_.addUnionWith(norm2); + avnorm2_ += fac*norm2; + } + } +} + +//=========================================================================== +void RevEngRegion::getRemainingPoints(vector<RevEngPoint*>& curr_pts, + vector<RevEngPoint*>& remaining) +//=========================================================================== +{ + remaining.clear(); + for (size_t ki=0; ki<group_points_.size(); ++ki) + { + auto it = std::find(curr_pts.begin(), curr_pts.end(), group_points_[ki]); + if (it == curr_pts.end()) + remaining.push_back(group_points_[ki]); + } +} + +//=========================================================================== + +void RevEngRegion::writeSubTriangulation(std::ostream& of) +{ + of << group_points_.size() << std::endl; + for (size_t kr=0; kr<group_points_.size(); ++kr) + { + vector<ftSamplePoint*> next = group_points_[kr]->getNeighbours(); + size_t nmb_next = next.size(); + for (int ka=(int)(next.size()-1); ka>=0; --ka) + { + RevEngPoint *pr = dynamic_cast<RevEngPoint*>(next[ka]); + if (pr->region() != this) + next.erase(next.begin()+ka); + } + + int bd = (next.size() < nmb_next) ? 1 : 0; + of << kr << " " << group_points_[kr]->getPoint() << " " << bd << std::endl; + of << next.size() << " "; + for (size_t kh=0; kh<next.size(); ++kh) + { + vector<RevEngPoint*>::iterator it = std::find(group_points_.begin(), + group_points_.end(), next[kh]); + if (it == group_points_.end()) + { +#ifdef DEBUG + std::cout << "writeSubTriangulation: missing connection" << std::endl; +#endif + } + else + { + size_t ix = it - group_points_.begin(); + of << ix << " "; + } + } + of << std::endl; + } +} + +void RevEngRegion::writeSurface(std::ostream& of) +{ + if (associated_sf_.size() == 0) + return; + shared_ptr<ParamSurface> surf = associated_sf_[0]->surface(); + shared_ptr<ElementarySurface> elemsf = + dynamic_pointer_cast<ElementarySurface,ParamSurface>(surf); + if (elemsf.get()) + { + // double umin = std::numeric_limits<double>::max(); + // double umax = std::numeric_limits<double>::lowest(); + // double vmin = std::numeric_limits<double>::max(); + // double vmax = std::numeric_limits<double>::lowest(); + // for (size_t ki=0; ki<group_points_.size(); ++ki) + // { + // Vector2D par = group_points_[ki]->getPar(); + // umin = std::min(umin, par[0]); + // umax = std::max(umax, par[0]); + // vmin = std::min(vmin, par[1]); + // vmax = std::max(vmax, par[1]); + // } + double umin = domain_[0]; + double umax = domain_[1]; + double vmin = domain_[2]; + double vmax = domain_[3]; + shared_ptr<ElementarySurface> elemsf2(elemsf->clone()); + if (elemsf2->instanceType() != Class_Plane && umax-umin > 2*M_PI) + { + umin = 0; + umax = 2*M_PI; + } + if (elemsf2->instanceType() != Class_Plane && elemsf2->instanceType() != Class_Sphere && + (umin < -2.0*M_PI || umax > 2.0*M_PI)) + { + umin = 0; + umax = 2*M_PI; + } + if (elemsf2->instanceType() == Class_Sphere && (umin < 0.0 || umax > 2.0*M_PI)) + { + umin = 0; + umax = 2*M_PI; + } + + if (elemsf2->instanceType() == Class_Sphere && + (vmax-vmin > M_PI || vmin < -0.5*M_PI || vmax > 0.5*M_PI)) + { + vmin = -0.5*M_PI; + vmax = 0.5*M_PI; + } + if (elemsf2->instanceType() == Class_Torus && + (vmax - vmin > 2*M_PI || vmin < -2.0*M_PI || vmax > 2.0*M_PI)) + { + vmin = 0; + vmax = 2*M_PI; + } + + if (elemsf2->isBounded()) + { + RectDomain dom = elemsf2->getParameterBounds(); + double udel = umax - umin; + double vdel = vmax - vmin; + if (dom.umax() - dom.umin() < 2.0*udel) + { + umin = dom.umin(); + umax = dom.umax(); + } + if (dom.vmax() - dom.vmin() < 2.0*vdel) + { + vmin = dom.vmin(); + vmax = dom.vmax(); + } + } + if (umax > umin && vmax > vmin) + elemsf2->setParameterBounds(umin, vmin, umax, vmax); + elemsf2->writeStandardHeader(of); + elemsf2->write(of); + } + else + { + surf->writeStandardHeader(of); + surf->write(of); + } +} + +void RevEngRegion::writeRegionInfo(std::ostream& of) +{ + double len = bbox_.low().dist(bbox_.high()); + double ll = 0.05*len; + of << "400 1 0 4 100 0 155 255" << std::endl; + of << group_points_.size() << std::endl; + for (size_t kr=0; kr<group_points_.size(); ++kr) + of << group_points_[kr]->getPoint() << std::endl; + of << "410 1 0 4 200 55 0 255" << std::endl; + of << group_points_.size() << std::endl; + for (size_t kr=0; kr<group_points_.size(); ++kr) + { + Vector3D xyz = group_points_[kr]->getPoint(); + Point xyz2(xyz[0], xyz[1], xyz[2]); + Point norm = group_points_[kr]->getLocFuncNormal(); + of << xyz2 << " " << xyz2 + ll*norm << std::endl; + } + + of << "410 1 0 4 0 100 155 255" << std::endl; + of << group_points_.size() << std::endl; + for (size_t kr=0; kr<group_points_.size(); ++kr) + { + Vector3D xyz = group_points_[kr]->getPoint(); + Point xyz2(xyz[0], xyz[1], xyz[2]); + Point vec = group_points_[kr]->getTriangNormal(); //minCurvatureVec(); + of << xyz2 << " " << xyz2 + ll*vec << std::endl; + } + + // double lambda[2]; + // Point eigen1, eigen2, eigen3; + // getPCA(lambda, eigen1, eigen2, eigen3); + // std::ofstream of2("points_two_tangents.txt"); + // of2 << group_points_.size() << std::endl; + // for (size_t kr=0; kr<group_points_.size(); ++kr) + // { + // Vector3D xyz = group_points_[kr]->getPoint(); + // Point norm = group_points_[kr]->getLocFuncNormal(); + // Point vec1 = eigen1 - (eigen1*norm)*norm; + // vec1.normalize(); + // Point vec2 = norm.cross(vec1); + // vec2.normalize(); + // of2 << xyz << " " << vec1 << " " << vec2 << std::endl; + // } +} + +void RevEngRegion::writeRegionPoints(std::ostream& of) +{ + of << "400 1 0 4 100 0 155 255" << std::endl; + of << group_points_.size() << std::endl; + for (size_t kr=0; kr<group_points_.size(); ++kr) + of << group_points_[kr]->getPoint() << std::endl; +} + +void RevEngRegion::writeAdjacentPoints(std::ostream& of) +{ + for (auto it=adjacent_regions_.begin(); it!=adjacent_regions_.end(); ++it) + { + (*it)->writeRegionPoints(of); + if ((*it)->hasSurface()) + { + shared_ptr<ParamSurface> tmp((*it)->getSurface(0)->surface()->clone()); + if (!tmp->isBounded()) + { + shared_ptr<ElementarySurface> elem = + dynamic_pointer_cast<ElementarySurface,ParamSurface>(tmp); + double dom[4]; + (*it)->getDomain(dom); + try { + if (elem.get()) + elem->setParameterBounds(dom[0], dom[2], dom[1], dom[3]); + } + catch (...) + { + } + } + tmp->writeStandardHeader(of); + tmp->write(of); + } + } +} + +void RevEngRegion::writeUnitSphereInfo(std::ostream& of) +{ + of << "400 1 0 4 100 0 155 255" << std::endl; + of << group_points_.size() << std::endl; + for (size_t kr=0; kr<group_points_.size(); ++kr) + { + RevEngPoint *pt = dynamic_cast<RevEngPoint*>(group_points_[kr]); + Point norm = pt->getLocFuncNormal(); + of << norm << std::endl; + } + Sphere sph(1.0, Point(0.0, 0.0, 0.0), Point(0.0, 0.0, 1.0), + Point(1.0, 0.0, 0.0)); + sph.writeStandardHeader(of); + sph.write(of); + + of << "400 1 0 4 0 100 155 255" << std::endl; + of << group_points_.size() << std::endl; + for (size_t kr=0; kr<group_points_.size(); ++kr) + { + RevEngPoint *pt = dynamic_cast<RevEngPoint*>(group_points_[kr]); + Point vec = pt->minCurvatureVec(); + of << vec << std::endl; + } + of << std::endl; +} diff --git a/compositemodel/src/RevEngUtils.C b/compositemodel/src/RevEngUtils.C new file mode 100644 index 00000000..de10ec7d --- /dev/null +++ b/compositemodel/src/RevEngUtils.C @@ -0,0 +1,3203 @@ +/* + * Copyright (C) 1998, 2000-2007, 2010, 2011, 2012, 2013 SINTEF ICT, + * Applied Mathematics, Norway. + * + * Contact information: E-mail: tor.dokken@sintef.no + * SINTEF ICT, Department of Applied Mathematics, + * P.O. Box 124 Blindern, + * 0314 Oslo, Norway. + * + * This file is part of GoTools. + * + * GoTools is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * GoTools 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with GoTools. If not, see + * <http://www.gnu.org/licenses/>. + * + * In accordance with Section 7(b) of the GNU Affero General Public + * License, a covered work must retain the producer line in every data + * file that is created or manipulated using GoTools. + * + * Other Usage + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial activities involving the GoTools library without + * disclosing the source code of your own applications. + * + * This file may be used in accordance with the terms contained in a + * written agreement between you and SINTEF ICT. + */ + +#include "GoTools/compositemodel/RevEngUtils.h" +#include "GoTools/compositemodel/ImplicitApprox.h" +#include "GoTools/utils/MatrixXD.h" +#include "GoTools/utils/LUDecomp.h" +#include "GoTools/creators/SmoothSurf.h" +#include "GoTools/creators/ApproxSurf.h" +#include "GoTools/creators/SmoothCurve.h" +#include "GoTools/creators/ApproxCurve.h" +#include "GoTools/geometry/SplineSurface.h" +#include "GoTools/geometry/SplineCurve.h" +#include "GoTools/geometry/Cylinder.h" +#include "GoTools/geometry/Cone.h" +#include "GoTools/geometry/Sphere.h" +#include "GoTools/geometry/Torus.h" +#include "GoTools/geometry/Plane.h" +#include "GoTools/geometry/Line.h" +#include "GoTools/geometry/BoundedSurface.h" +#include "GoTools/geometry/SISLconversion.h" +#include "GoTools/geometry/GeometryTools.h" +#include "GoTools/geometry/GoIntersections.h" +#include "GoTools/geometry/SplineDebugUtils.h" +#include "sislP.h" +#include "newmat.h" +#include "newmatap.h" +#include <fstream> + +using namespace Go; +using std::vector; +using std::pair; + +//#define DEBUG +//#define DEBUG_BLEND +//#define DEBUG_CONE +//#define DEBUG_APPROX + +typedef MatrixXD<double, 3> Matrix3D; + +//=========================================================================== +void RevEngUtils::principalAnalysis(std::vector<RevEngPoint*>& points, + double lambda[3], double eigenvec[3][3]) +//=========================================================================== +{ + if (points.size() < 5) + return; + vector<Point> remaining(points.size()-1); + Vector3D xyz = points[0]->getPoint(); + Point curr(xyz[0], xyz[1], xyz[2]); + for (size_t ki=1; ki<points.size(); ++ki) + { + xyz = points[ki]->getPoint(); + Point curr2(xyz[0], xyz[1], xyz[2]); + remaining[ki-1] = curr2; + } + principalAnalysis(curr, remaining, lambda, eigenvec); +} + +//=========================================================================== +void RevEngUtils::principalAnalysis(Point& curr, vector<Point>& points, + double lambda[3], double eigenvec[3][3]) +//=========================================================================== +{ + // Compute covariance matrix + int numpt = (int)points.size(); + double comat[3][3]; + Point mean = curr; + for (int kr=0; kr<numpt; ++kr) + mean += points[kr]; + mean /= (double)(numpt+1); + + vector<double> wgt(numpt+1); + double div = (double)((numpt+1)*(numpt+1)); + wgt[0] = (mean.dist(curr))/div; + for (int kr=0; kr<numpt; ++kr) + { + double dr2 = mean.dist2(points[kr]); + wgt[kr+1] = exp(-dr2/div); + } + + for (int ki=0; ki<3; ++ki) + for (int kj=0; kj<3; ++kj) + { + double tmp = 0.0; + tmp += wgt[0]*(curr[ki] - mean[ki])*(curr[kj] - mean[kj]); + for (int kr=0; kr<numpt; ++kr) + { + tmp += wgt[kr+1]*(points[kr][ki] - mean[ki])*(points[kr][kj] - mean[kj]); + } + comat[ki][kj] = tmp/(double)(numpt); + } + + // Compute singular values + NEWMAT::Matrix nmat; + nmat.ReSize(3, 3); + for (int ki = 0; ki < 3; ++ki) { + for (int kj = 0; kj < 3; ++kj) { + nmat.element(ki, kj) = comat[ki][kj]; + } + } + + static NEWMAT::DiagonalMatrix diag; + static NEWMAT::Matrix V; + try { + NEWMAT::SVD(nmat, diag, nmat, V); + } catch(...) { + //std::cout << "Exception in SVD" << std::endl; + return; + } + + // Singular values + for (int ki=0; ki<3; ++ki) + { + lambda[ki] = diag.element(ki, ki); + for (int kj=0; kj<3; ++kj) + eigenvec[ki][kj] = V.element(kj, ki); + } +} + + +//=========================================================================== +void RevEngUtils::computeLocFunc(Point& curr, std::vector<Point>& points, + Point& vec1, Point& vec2, Point& normal, Point& mincvec, + double& minc, Point& maxcvec, double& maxc, + double& currdist, double& avdist) +//=========================================================================== +{ + // Transform points to coordinate system given by vec1 (x-axis) and vec2 (y-axis) + Matrix3D mat1, mat2, rotmat; + Vector3D vec1_2(vec1[0], vec1[1], vec1[2]); + Vector3D vec2_2(vec2[0], vec2[1], vec2[2]); + Vector3D xaxis(1, 0, 0); + Vector3D zaxis(0, 0, 1); + mat1.setToRotation(vec1_2, xaxis); + Vector3D v1 = mat1*vec1_2; + Vector3D vec2_3 = mat1*vec2_2; + mat2.setToRotation(vec2_3, zaxis); + Vector3D v2 = mat2*vec2_3; + rotmat = mat2*mat1; + //rotmat.identity(); + + // Perform rotation and sort parameter values and z-value + int nmbpts = (int)points.size() + 1; + vector<double> par(2*nmbpts); + vector<double> zval(nmbpts); + par[0] = curr[0]; + par[1] = curr[1]; + zval[0] = curr[2]; + for (int ki=1; ki<nmbpts; ++ki) + { + Point dv = points[ki-1] - curr; + Vector3D dv2(dv[0], dv[1], dv[2]); + Vector3D dvrot = rotmat*dv2; + //Vector3D dvrot = mat2*dvrot0; + par[2*ki] = curr[0] + dvrot[0]; + par[2*ki+1] = curr[1] + dvrot[1]; + zval[ki] = curr[2] + dvrot[2]; + } + + // Approximate z-component by biquadratic Bezier function in x and y + int order = 3; + shared_ptr<SplineSurface> locsf = RevEngUtils::surfApprox(zval, 1, par, order, + order, order, order); + + vector<double> coefs2(3*order*order); + std::vector<double>::iterator cf = locsf->coefs_begin(); + for (int ka=0; ka<order; ++ka) + { + double vpar = locsf->basis_v().grevilleParameter(ka); + for (int kb=0; kb<order; ++kb, ++cf) + { + double upar = locsf->basis_u().grevilleParameter(kb); + coefs2[(ka*order+kb)*3] = upar; + coefs2[(ka*order+kb)*3+1] = vpar; + coefs2[(ka*order+kb)*3+2] = *cf; + } + } + shared_ptr<SplineSurface> tmp(new SplineSurface(order, order, order, order, + locsf->basis_u().begin(), + locsf->basis_v().begin(), &coefs2[0], 3)); +#ifdef DEBUG + int writesurface = 0; + if (writesurface) + { + std::ofstream of("approx_sf.g2"); + tmp->writeStandardHeader(of); + tmp->write(of); + of << "400 1 0 4 0 255 0 255" << std::endl; + of << 1 << std::endl; + of << curr << std::endl; + of << "400 1 0 4 255 0 0 255" << std::endl; + of << nmbpts << std::endl; + for (int ka=0; ka<nmbpts; ++ka) + { + Point tmppt(par[2*ka], par[2*ka+1], zval[ka]); + of << tmppt << std::endl; + } + } +#endif + + // Compute surface normal in curr + vector<Point> der(3); + locsf->point(der, par[0], par[1], 1); + Vector3D norm(-der[1][0], -der[2][0], 1.0); + norm.normalize(); + + // Accuracy of approximation + currdist = fabs(zval[0] - der[0][0]); + avdist = currdist; + for (int ki=1; ki<nmbpts; ++ki) + { + Point pos; + locsf->point(pos, par[2*ki], par[2*ki+1]); + avdist += fabs(zval[ki] - pos[0]); + } + avdist /= (double)nmbpts; + + // Compute principal curvatures in curr + shared_ptr<SISLSurf> sislsf(GoSurf2SISL(*locsf, false)); + int left1 = 0, left2 = 0; + int stat = 0; + double k1, k2; + double d1[2], d2[2]; + s2542(sislsf.get(), 0, 0, 0, &par[0], &left1, &left2, &k1, &k2, d1, d2, &stat); + Vector3D du(1.0, 0.0, der[1][0]); + Vector3D dv(0.0, 1.0, der[2][0]); + Vector3D cvec1 = d1[0]*du + d1[1]*dv; + Vector3D cvec2 = d2[0]*du + d2[1]*dv; + minc = k1; + maxc = k2; + + // Vector3D origin(par[0], par[1], zval[0]); + // of << "410 1 0 4 0 0 0 255" << std::endl; + // of << "1" << std::endl; + // of << origin << " " << origin+norm << std::endl; + + // of << "410 1 0 4 0 55 155 255" << std::endl; + // of << "1" << std::endl; + // of << origin << " " << origin+cvec1 << std::endl; + + + // of << "410 1 0 4 155 55 0 255" << std::endl; + // of << "1" << std::endl; + // of << origin << " " << origin+cvec2 << std::endl; + + + + // Transform results to original coordinate system + Matrix3D mat3, mat4, rotmat2; + mat4.setToRotation(zaxis, vec2_3); + mat3.setToRotation(xaxis, vec1_2); + rotmat2 = mat3*mat4; + //rotmat2.identity(); + //Vector3D norm0 = mat4*norm; + Vector3D norm2 = rotmat2*norm; + normal = Point(norm2[0], norm2[1], norm2[2]); + + Vector3D cvec3 = rotmat2*cvec1; + mincvec = Point(cvec3[0], cvec3[1],cvec3[2]); + Vector3D cvec4 = rotmat2*cvec2; + maxcvec = Point(cvec4[0], cvec4[1],cvec4[2]); + + int stop_break = 1; +} + +//=========================================================================== +void RevEngUtils::smoothSurf(shared_ptr<SplineSurface>& surf, int fixed) +//=========================================================================== +{ + SmoothSurf smooth; + int ncoef1 = surf->numCoefs_u(); + int ncoef2 = surf->numCoefs_v(); + vector<int> coef_known(ncoef1*ncoef2, 0); + for (int ka=0; ka<ncoef1; ++ka) + { + for (int kb=0; kb<fixed; kb++) + { + coef_known[kb*ncoef1+ka] = 1; + coef_known[(ncoef2-kb-1)*ncoef1+ka] = 1; + } + } + for (int kb=fixed; kb<ncoef2-fixed; ++kb) + { + for (int ka=0; ka<fixed; ++ka) + { + coef_known[kb*ncoef1+ka] = 1; + coef_known[(kb+1)*ncoef1-ka-1] = 1; + } + } + + + int close1 = GeometryTools::analyzePeriodicityDerivs(*surf, 0, 1); + int close2 = GeometryTools::analyzePeriodicityDerivs(*surf, 1, 1); + int seem[2]; + seem[0] = (close1 >= 0) ? 1 : 0; + seem[1] = (close2 >= 0) ? 1 : 0; + shared_ptr<SplineSurface> surf2(surf->clone()); + smooth.attach(surf2, seem, &coef_known[0]); + + double wgt1 = 0.0, wgt2 = 1.0, wgt3 = 0.0; + smooth.setOptimize(wgt1, wgt2, wgt3); + shared_ptr<SplineSurface> surf3; + smooth.equationSolve(surf3); + std::swap(surf, surf3); +} + +//=========================================================================== +shared_ptr<SplineSurface> +RevEngUtils::surfApprox(vector<double>& data, int dim, vector<double>& param, + int order1, int order2, int ncoef1, int ncoef2, + bool close1, bool close2, + int max_iter, double tol, double& maxd, double& avd, + int& num_out, vector<double>& parvals, double belt_frac) +//=========================================================================== +{ + // Create initial spline space + double umin = std::numeric_limits<double>::max(); + double umax = std::numeric_limits<double>::lowest(); + double vmin = std::numeric_limits<double>::max(); + double vmax = std::numeric_limits<double>::lowest(); + for (size_t ki=0; ki<param.size(); ki+=2) + { + umin = std::min(umin, param[ki]); + umax = std::max(umax, param[ki]); + vmin = std::min(vmin, param[ki+1]); + vmax = std::max(vmax, param[ki+1]); + } + double udel = (umax - umin); + double vdel = (vmax - vmin); + if (!close1) + { + umin -= belt_frac*udel; + umax += belt_frac*udel; + } + if (!close2) + { + vmin -= belt_frac*vdel; + vmax += belt_frac*vdel; + } + udel = (umax - umin)/(double)(ncoef1 - order1 + 1); + vdel = (vmax - vmin)/(double)(ncoef2 - order2 + 1); + vector<double> et1(order1+ncoef1); + vector<double> et2(order2+ncoef2); + vector<double> coef(ncoef1*ncoef2*dim, 0.0); + for (int ka=0; ka<order1; ++ka) + { + et1[ka] = umin; + et1[ka+ncoef1] = umax; + } + for (int ka=0; ka<order2; ++ka) + { + et2[ka] = vmin; + et2[ka+ncoef2] = vmax; + } + for (int ka=0; ka<ncoef1-order1; ++ka) + et1[order1+ka] = umin + (ka+1)*udel; + for (int ka=0; ka<ncoef2-order2; ++ka) + et2[order2+ka] = vmin + (ka+1)*vdel; + + + shared_ptr<SplineSurface> surf(new SplineSurface(ncoef1, ncoef2, order1, + order2, &et1[0], + &et2[0], &coef[0], dim)); + shared_ptr<SplineSurface> surf1(new SplineSurface(ncoef1, ncoef2, order1, + order2, &et1[0], + &et2[0], &coef[0], dim)); + + // Approximate + SmoothSurf approx2; + vector<int> coef_known(ncoef1*ncoef2, 0); + int seem[2]; + seem[0] = close1 ? 1 : 0; + seem[1] = close2 ? 1 : 0; + int nmbpts = (int)data.size()/dim; + vector<double> ptwgt(nmbpts, 1.0); + approx2.attach(surf1, seem, &coef_known[0]); + + //double wgt1 = 0.0, wgt2 = 0.001, wgt3 = 0.001; + double wgt1 = 0.0, wgt2 = 0.001, wgt3 = 0.001; + double approxwgt = 1.0 - wgt1 - wgt2 - wgt3; + approx2.setOptimize(wgt1, wgt2, wgt3); + approx2.setLeastSquares(data, param, ptwgt, approxwgt); + shared_ptr<SplineSurface> surf3; + approx2.equationSolve(surf3); +#ifdef DEBUG + std::ofstream of("first_approx.g2"); + surf3->writeStandardHeader(of); + surf3->write(of); +#endif + + ApproxSurf approx(surf3, data, param, dim, tol); + //ApproxSurf approx(surf3, data, param, dim, tol, 0, false, true, 0, true); + approx.setMBA(true); + approx.setFixBoundary(false); + double acc_frac = 0.6; + approx.setAccuracyCrit(1, acc_frac); + shared_ptr<SplineSurface> surf2 = approx.getApproxSurf(maxd, avd, num_out, max_iter); + if (surf2.get()) + parvals = approx.getParvals(); + return surf2; +} + +//=========================================================================== +shared_ptr<SplineSurface> RevEngUtils::surfApprox(vector<double>& data, int dim, + vector<double>& param, int order1, + int order2, int nmb_coef1, int nmb_coef2, + double del) +//=========================================================================== +{ + // Define spline space + double umin, umax, vmin, vmax; + umin = umax = param[0]; + vmin = vmax = param[1]; + for (size_t kj=2; kj<param.size(); kj+=2) + { + umin = std::min(umin, param[kj]); + umax = std::max(umax, param[kj]); + vmin = std::min(vmin, param[kj+1]); + vmax = std::max(vmax, param[kj+1]); + } + umin -= del; + umax += del; + vmin -= del; + vmax += del; + + return surfApprox(data, dim, param, order1, order2, nmb_coef1, nmb_coef2, + umin, umax, vmin, vmax); +} + +//=========================================================================== +shared_ptr<SplineSurface> RevEngUtils::surfApprox(vector<double>& data, int dim, + vector<double>& param, int order1, + int order2, int nmb_coef1, int nmb_coef2, + double umin, double umax, + double vmin, double vmax) +//=========================================================================== +{ + double udel = (umax - umin)/(double)(nmb_coef1-order1+1); + double vdel = (vmax - vmin)/(double)(nmb_coef2-order2+1); + + vector<double> knots1(order1+nmb_coef1), knots2(order2+nmb_coef2); + for (int ka=0; ka<order1; ++ka) + { + knots1[ka] = umin; + knots1[nmb_coef1+ka] = umax; + } + for (int ka=order1; ka<nmb_coef1; ++ka) + knots1[ka] = umin + (ka-order1+1)*udel; + + for (int ka=0; ka<order2; ++ka) + { + knots2[ka] = vmin; + knots2[nmb_coef2+ka] = vmax; + } + for (int ka=order2; ka<nmb_coef2; ++ka) + knots2[ka] = vmin + (ka-order2+1)*vdel; + + + vector<double> coefs((nmb_coef1+order1)*(nmb_coef2+order2)*dim, 0.0); + shared_ptr<SplineSurface> bez(new SplineSurface(nmb_coef1, nmb_coef2, order1, order2, + &knots1[0], &knots2[0], &coefs[0], dim)); + + // Approximate + SmoothSurf approx; + vector<int> coef_known((nmb_coef1+order1)*(nmb_coef2+order2), 0); + int seem[2]; + seem[0] = seem[1] = 0; + int nmbpts = (int)data.size()/dim; + vector<double> ptwgt(nmbpts, 1.0); + approx.attach(bez, seem, &coef_known[0]); + + //double wgt1 = 0.0, wgt2 = 0.001, wgt3 = 0.001; + double wgt1 = 0.0, wgt2 = 0.05, wgt3 = 0.05; + double approxwgt = 1.0 - wgt1 - wgt2 - wgt3; + approx.setOptimize(wgt1, wgt2, wgt3); + approx.setLeastSquares(data, param, ptwgt, approxwgt); + + shared_ptr<SplineSurface> surf; + approx.equationSolve(surf); + return surf; + } + +//=========================================================================== +bool RevEngUtils::parameterizeOnPrimary(vector<RevEngPoint*>& points, + shared_ptr<ParamSurface> surf, + vector<double>& data, vector<double>& param, + int& inner1, int& inner2, bool& close1, + bool& close2) +//=========================================================================== +{ + double eps = 1.0e-2; + double angtol = 0.1; + + // Make sure to use an untrimmed surface + shared_ptr<ParamSurface> sf = surf; + shared_ptr<BoundedSurface> bdsf = dynamic_pointer_cast<BoundedSurface,ParamSurface>(sf); + if (bdsf.get()) + sf = bdsf->underlyingSurface(); + shared_ptr<Cylinder> cyl = dynamic_pointer_cast<Cylinder,ParamSurface>(sf); + shared_ptr<Cone> cone = dynamic_pointer_cast<Cone,ParamSurface>(sf); + shared_ptr<Sphere> sph = dynamic_pointer_cast<Sphere,ParamSurface>(sf); + shared_ptr<Torus> torus = dynamic_pointer_cast<Torus,ParamSurface>(sf); + close1 = (cyl.get() || cone.get() || sph.get() || torus.get()); + close2 = (sph.get() || torus.get()); + RectDomain dom = sf->containingDomain(); + double u1 = dom.umin(); + double u2 = dom.umax(); + double udel = u2 - u1; + double v1 = dom.vmin(); + double v2 = dom.vmax(); + double vdel = v2 - v1; + + // Parameterize + int dim = surf->dimension(); + param.resize(2*points.size()); + data.reserve(dim*points.size()); + double umin = std::numeric_limits<double>::max(); + double umax = std::numeric_limits<double>::lowest(); + double vmin = std::numeric_limits<double>::max(); + double vmax = std::numeric_limits<double>::lowest(); + double sfac = 0.5; + for (size_t ki=0; ki<points.size(); ++ki) + { + Vector3D xyz = points[ki]->getPoint(); + Point pos(xyz[0], xyz[1], xyz[2]); + double upar, vpar, dist; + Point close; + sf->closestPoint(pos, upar, vpar, close, dist, eps); + + if (sf->isBounded() && dist > 0.1) //eps) TEST + { + // Check boundary + double uparbd, vparbd, distbd; + Point closebd; + double seed[2]; + seed[0] = upar; + seed[1] = vpar; + RectDomain dom = sf->containingDomain(); + sf->closestBoundaryPoint(pos, uparbd, vparbd, closebd, distbd, eps, &dom, seed); + if (fabs(distbd - dist) < 0.1*dist) + { + // Angular check to see if a true closest point is found + Point norm; + sf->normal(norm, upar, vpar); + Point vec = pos - close; + double ang = norm.angle(vec); + ang = std::min(ang, fabs(M_PI - ang)); + if (ang > angtol) + return false; + } + } + + // Check with seam + // if (ki > 0 && close1 && ((upar-u1 < umin-upar && u2-umax < umin-u1) || + // (u2-upar < upar-umax && umin-u1 < u2-umax))) + // if (ki > 0 && close1 && (upar < umin || upar > umax) && + // (fabs(umin-upar+udel) < fabs(upar-umin) || fabs(upar+udel-umax) < fabs(umax-upar))) + if (ki > 0 && close1 && (upar < umin || upar > umax) && + std::min(fabs(umin-upar+udel),fabs(upar+udel-umax)) < std::min(fabs(upar-umin),fabs(upar-umax))) + { + // if (ki >= 2) + // { + // // Compare distances + // double d1 = points[ki-2]->pntDist(points[ki-1]); + // double d2 = points[ki-1]->pntDist(points[ki]); + // Point p1(param[2*(ki-2)], param[2*(ki-2)+1]); + // Point p2(param[2*(ki-1)], param[2*(ki-1)+1]); + // Point p3(upar,vpar); + // double dp1 = p1.dist(p2); + // double dp2 = p2.dist(p3); + // if (dp1/dp2 < sfac*d1/d2) + // { + if (upar-u1 < u2-upar) + upar += (u2-u1); + else + upar -= (u2-u1); + // } + + // int stop_break1 = 1; + // } + } + // if (ki > 0 && close2 && ((vpar-v1 < vmin-vpar && v2-vmax < vmin-v1) || + // (v2-vpar < vpar-vmax && vmin-v1 < v2-vmax))) + // if (ki > 0 && close2 && (vpar < vmin || vpar > vmax) && + // (fabs(vmin-vpar+vdel) < fabs(vpar-vmin) || fabs(vpar+vdel-vmax) < fabs(vpar-vmax))) + if (ki > 0 && close2 && (vpar < vmin || vpar > vmax) && + std::min(fabs(vmin-vpar+vdel),fabs(vpar+vdel-vmax)) < std::min(fabs(vpar-vmin),fabs(vpar-vmax))) + { + // if (ki >= 2) + // { + // // Compare distances + // double d1 = points[ki-2]->pntDist(points[ki-1]); + // double d2 = points[ki-1]->pntDist(points[ki]); + // Point p1(param[2*(ki-2)], param[2*(ki-2)+1]); + // Point p2(param[2*(ki-1)], param[2*(ki-1)+1]); + // Point p3(upar,vpar); + // double dp1 = p1.dist(p2); + // double dp2 = p2.dist(p3); + // if (dp1/dp2 < sfac*d1/d2) + // { + if (vpar-v1 < v2-vpar) + vpar += (v2-v1); + else + vpar -= (v2-v1); + // } + + // int stop_break2 = 1; + // } + } + param[2*ki] = upar; + param[2*ki+1] = vpar; + umin = std::min(umin, upar); + umax = std::max(umax, upar); + vmin = std::min(vmin, vpar); + vmax = std::max(vmax, vpar); + data.insert(data.end(), pos.begin(), pos.end()); + } + + if (close1 && umax-umin < 2*M_PI-eps) + close1 = false; + if (close2 && vmax-vmin < 2*M_PI-eps) + close2 = false; + + // Reparameterize for surfaces with circular properties + inner1 = inner2 = 0; + if (cyl.get()) + { + double rad = cyl->getRadius(); + for (size_t ki=0; ki<param.size(); ki+=2) + param[ki] *= rad; + inner1 = 2.0*(umax - umin)/M_PI; + } + + if (cone.get()) + { + double rad1 = cone->radius(0.0, vmin); + double rad2 = cone->radius(0.0, vmax); + double rad = 0.5*(rad1 + rad2); + for (size_t ki=0; ki<param.size(); ki+=2) + param[ki] *= rad; + inner1 = 2.0*(umax - umin)/M_PI; + } + + if (sph.get()) + { + double rad = sph->getRadius(); + for (size_t ki=0; ki<param.size(); ++ki) + param[ki] *= rad; + inner1 = 2.0*(umax - umin)/M_PI; + inner2 = 2.0*(vmax - vmin)/M_PI; + } + + if (torus.get()) + { + double rad1 = torus->getMajorRadius(); + double rad2 = torus->getMinorRadius(); + for (size_t ki=0; ki<param.size(); ki+=2) + { + param[ki] *= rad1; + param[ki+1] *= rad2; + } + inner1 = 2.0*(umax - umin)/M_PI; + inner2 = 2.0*(vmax - vmin)/M_PI; + } + return true; +} + +//=========================================================================== +void RevEngUtils::parameterizeWithPlane(vector<RevEngPoint*>& pnts, + const BoundingBox& bbox, + const Point& vec1, const Point& vec2, + vector<double>& data, vector<double>& param) +//=========================================================================== +{ + vector<Point> pos(pnts.size()); + for (size_t ki=0; ki<pnts.size(); ++ki) + { + Vector3D xyz = pnts[ki]->getPoint(); + pos[ki] = Point(xyz[0], xyz[1], xyz[2]); + } + + parameterizeWithPlane(pos, bbox, vec1, vec2, data, param); +} + +//=========================================================================== +void RevEngUtils::parameterizeWithPlane(vector<Point>& pnts, const BoundingBox& bbox, + const Point& vec1, const Point& vec2, + vector<double>& data, vector<double>& param) +//=========================================================================== +{ + double eps = 1.0e-6; + Point mid = 0.5*(bbox.low() + bbox.high()); + int dim = mid.dimension(); + double diag = bbox.low().dist(bbox.high()); + int order = 2; + double et[4]; + et[0] = et[1] = -diag; + et[2] = et[3] = diag; + vector<double> coefs; + int sgn1, sgn2; + int ka, kb; + for (kb=0, sgn2=-1; kb<2; ++kb, sgn2=1) + for (ka=0, sgn1=-1; ka<2; ++ka, sgn1=1) + { + Point pos = mid+sgn1*diag*vec1+sgn2*diag*vec2; + coefs.insert(coefs.end(), pos.begin(), pos.end()); + } + + shared_ptr<SplineSurface> surf(new SplineSurface(order, order, order, order, &et[0], + &et[0], coefs.begin(), dim)); +#ifdef DEBUG + std::ofstream of("parplane.g2"); + surf->writeStandardHeader(of); + surf->write(of); +#endif + + param.resize(2*pnts.size()); + data.reserve(dim*pnts.size()); + for (size_t ki=0; ki<pnts.size(); ++ki) + { + double upar, vpar, dist; + Point close; + surf->closestPoint(pnts[ki], upar, vpar, close, dist, eps); + param[2*ki] = upar; + param[2*ki+1] = vpar; + data.insert(data.end(), pnts[ki].begin(), pnts[ki].end()); + } +} + +//=========================================================================== +void RevEngUtils::computeAxis(vector<pair<vector<RevEngPoint*>::iterator, + vector<RevEngPoint*>::iterator> >& points, + Point& axis, Point& Cx, Point& Cy) +//=========================================================================== +{ + double Cmat[3][3]; + for (int ka=0; ka<3; ++ka) + for (int kb=0; kb<3; ++kb) + Cmat[ka][kb] = 0.0; + for (size_t ki=0; ki<points.size(); ++ki) + { + vector<RevEngPoint*>::iterator start = points[ki].first; + vector<RevEngPoint*>::iterator end = points[ki].second; + for (int ka=0; ka<3; ++ka) + for (int kb=0; kb<3; ++kb) + { + for (auto it=start; it!=end; ++it) + { + RevEngPoint *pt = *it; + Point norm1 = pt->getLocFuncNormal(); + Point norm2 = pt->getTriangNormal(); + Point norm = norm1; //0.5*(norm1 + norm2); + Cmat[ka][kb] += norm[ka]*norm[kb]; + //Cmat[ka][kb] += norm2[ka]*norm2[kb]; + } + } + } + + // Compute singular values + NEWMAT::Matrix nmat; + nmat.ReSize(3, 3); + for (int ka = 0; ka < 3; ++ka) { + for (int kb = 0; kb < 3; ++kb) { + nmat.element(ka, kb) = Cmat[ka][kb]; + } + } + + static NEWMAT::DiagonalMatrix diag; + static NEWMAT::Matrix V; + try { + NEWMAT::SVD(nmat, diag, nmat, V); + } catch(...) { + //std::cout << "Exception in SVD" << std::endl; + exit(-1); + } + Cx = Point(V.element(0,0), V.element(1,0), V.element(2,0)); + Cy = Point(V.element(0,1), V.element(1,1), V.element(2,1)); + axis = Point(V.element(0,2), V.element(1,2), V.element(2,2)); + +} + + +//=========================================================================== +void RevEngUtils::computeAxis(vector<Point>& points, + Point& axis, Point& Cx, Point& Cy) +//=========================================================================== +{ + double Cmat[3][3]; + for (int ka=0; ka<3; ++ka) + for (int kb=0; kb<3; ++kb) + { + Cmat[ka][kb] = 0.0; + for (size_t ki=0; ki<points.size(); ++ki) + { + Cmat[ka][kb] += points[ki][ka]*points[ki][kb]; + } + } + + // Compute singular values + NEWMAT::Matrix nmat; + nmat.ReSize(3, 3); + for (int ka = 0; ka < 3; ++ka) { + for (int kb = 0; kb < 3; ++kb) { + nmat.element(ka, kb) = Cmat[ka][kb]; + } + } + + static NEWMAT::DiagonalMatrix diag; + static NEWMAT::Matrix V; + try { + NEWMAT::SVD(nmat, diag, nmat, V); + } catch(...) { + //std::cout << "Exception in SVD" << std::endl; + exit(-1); + } + Cx = Point(V.element(0,0), V.element(1,0), V.element(2,0)); + Cy = Point(V.element(0,1), V.element(1,1), V.element(2,1)); + axis = Point(V.element(0,2), V.element(1,2), V.element(2,2)); + +} + + +//=========================================================================== +void RevEngUtils::coneAxis(vector<pair<vector<RevEngPoint*>::iterator, + vector<RevEngPoint*>::iterator> >& points, + Point& axis, Point& Cx, Point& Cy) +//=========================================================================== +{ + size_t numpt = 0; + for (size_t ki=0; ki<points.size(); ++ki) + { + numpt += (points[ki].second - points[ki].first); + } + double wgt = 1.0/(double)numpt; + + Point mid(3); + for (size_t ki=0; ki<points.size(); ++ki) + { + vector<RevEngPoint*>::iterator start = points[ki].first; + vector<RevEngPoint*>::iterator end = points[ki].second; + for (auto it=start; it!=end; ++it) + { + RevEngPoint *pt = *it; + Point norm = pt->getLocFuncNormal(); + mid += wgt*norm; + } + } + + double Cmat[3][3]; + for (size_t ki=0; ki<points.size(); ++ki) + { + vector<RevEngPoint*>::iterator start = points[ki].first; + vector<RevEngPoint*>::iterator end = points[ki].second; + for (int ka=0; ka<3; ++ka) + for (int kb=0; kb<3; ++kb) + { + Cmat[ka][kb] = 0.0; + for (auto it=start; it!=end; ++it) + { + RevEngPoint *pt = *it; + Point norm = pt->getLocFuncNormal(); + Point vec = norm - mid; + Cmat[ka][kb] += vec[ka]*vec[kb]; + } + } + } + + // Compute singular values + NEWMAT::Matrix nmat; + nmat.ReSize(3, 3); + for (int ka = 0; ka < 3; ++ka) { + for (int kb = 0; kb < 3; ++kb) { + nmat.element(ka, kb) = Cmat[ka][kb]; + } + } + + static NEWMAT::DiagonalMatrix diag; + static NEWMAT::Matrix V; + try { + NEWMAT::SVD(nmat, diag, nmat, V); + } catch(...) { + //std::cout << "Exception in SVD" << std::endl; + exit(-1); + } + Cx = Point(V.element(0,0), V.element(1,0), V.element(2,0)); + Cy = Point(V.element(0,1), V.element(1,1), V.element(2,1)); + axis = Point(V.element(0,2), V.element(1,2), V.element(2,2)); + +} + +//=========================================================================== +void RevEngUtils::coneApex(vector<pair<vector<RevEngPoint*>::iterator, + vector<RevEngPoint*>::iterator> >& points, + Point axis, Point& apex, double& phi) +//=========================================================================== +{ + double Mmat[3][3], Mi[3][3]; + double bvec[3], bi[3]; + for (int ka=0; ka<3; ++ka) + { + bvec[ka] = 0.0; + for (int kb=0; kb<3; ++kb) + Mmat[ka][kb] = 0.0; + } + + int nmb = 0; + for (size_t ki=0; ki<points.size(); ++ki) + nmb += (int)(points[ki].second - points[ki].first); + + vector<Point> dird; + vector<Point> pp; + dird.reserve(nmb); + pp.reserve(nmb); + double wg = 1.0/(double)nmb; + for (size_t ki=0; ki<points.size(); ++ki) + { + vector<RevEngPoint*>::iterator start = points[ki].first; + vector<RevEngPoint*>::iterator end = points[ki].second; + for (auto it=start; it!=end; ++it) + { + RevEngPoint *pt = *it; + Point norm = pt->getLocFuncNormal(); + Point tmp = norm.cross(axis); + Point di = tmp.cross(norm); + di.normalize_checked(); + dird.push_back(di); + Vector3D xyz = pt->getPoint(); + Point pos(xyz[0], xyz[1], xyz[2]); + pp.push_back(pos); + + for (int ka=0; ka<3; ++ka) + for (int kb=0; kb<3; ++kb) + { + if (ka == kb) + continue; + Mi[ka][kb] = -di[ka]*di[kb]; + } + Mi[0][0] = di[1]*di[1] + di[2]*di[2]; + Mi[1][1] = di[0]*di[0] + di[2]*di[2]; + Mi[2][2] = di[0]*di[0] + di[1]*di[1]; + + bi[0] = pos[0]*di[1]*di[1] - pos[1]*di[0]*di[1] - pos[2]*di[0]*di[2] + pos[0]*di[2]*di[2]; + bi[1] = pos[1]*di[2]*di[2] - pos[2]*di[1]*di[2] - pos[0]*di[1]*di[0] + pos[1]*di[0]*di[0]; + bi[2] = pos[2]*di[0]*di[0] - pos[0]*di[2]*di[0] - pos[1]*di[2]*di[1] + pos[2]*di[1]*di[1]; + + for (int ka=0; ka<3; ++ka) + { + bvec[ka] += wg*bi[ka]; + for (int kb=0; kb<3; ++kb) + Mmat[ka][kb] += wg*Mi[ka][kb]; + } + } + } + +#ifdef DEBUG + std::ofstream of("directions.g2"); + of << "410 1 0 4 155 200 0 255" << std::endl; + of << dird.size() << std::endl; + for (size_t ki=0; ki<dird.size(); ++ki) + of << pp[ki] << " " << pp[ki]+dird[ki] << std::endl; +#endif + + double det = 0.0; + int sgn = 1; + int ka, kb, kc; + double ax=0.0, ay=0.0, az=0.0; + // for (ka=0; ka<3; ++ka, sgn*=-1) + // { + // kb = (ka+1)%3; + // kc = (kb+1)%3; + // det += sgn*Mmat[0][ka]*(Mmat[1][kb]*Mmat[2][kc]-Mmat[2][kb]*Mmat[1][kc]); + // ax += sgn*bvec[ka]*(Mmat[1][kb]*Mmat[2][kc]-Mmat[2][kb]*Mmat[1][kc]); + // ay += sgn*Mmat[0][ka]*(bvec[kb]*Mmat[2][kc]-Mmat[2][kb]*bvec[kc]); + // az += sgn*Mmat[0][ka]*(Mmat[1][kb]*bvec[kc]-bvec[kb]*Mmat[1][kc]); + // } + // apex = Point(ax/det, ay/det, az/det); + + double det2 = Mmat[0][0]*(Mmat[1][1]*Mmat[2][2] - Mmat[1][2]*Mmat[2][1]) - + Mmat[0][1]*(Mmat[1][0]*Mmat[2][2] - Mmat[1][2]*Mmat[2][0]) + + Mmat[0][2]*(Mmat[1][0]*Mmat[2][1] - Mmat[1][1]*Mmat[2][0]); + double ax2 = bvec[0]*(Mmat[1][1]*Mmat[2][2] - Mmat[1][2]*Mmat[2][1]) - + bvec[1]*(Mmat[1][0]*Mmat[2][2] - Mmat[1][2]*Mmat[2][0]) + + bvec[2]*(Mmat[1][0]*Mmat[2][1] - Mmat[1][1]*Mmat[2][0]); + double ay2 = Mmat[0][0]*(bvec[1]*Mmat[2][2] - bvec[2]*Mmat[2][1]) - + Mmat[0][1]*(bvec[0]*Mmat[2][2] - bvec[2]*Mmat[2][0]) + + Mmat[0][2]*(bvec[0]*Mmat[2][1] - bvec[1]*Mmat[2][0]); + double az2 = Mmat[0][0]*(Mmat[1][1]*bvec[2] - Mmat[1][2]*bvec[1]) - + Mmat[0][1]*(Mmat[1][0]*bvec[2] - Mmat[1][2]*bvec[0]) + + Mmat[0][2]*(Mmat[1][0]*bvec[1] - Mmat[1][1]*bvec[0]); + apex = (fabs(det2) < 1.0e-6) ? Point(0.0, 0.0, 0.0) : Point(ax2/det2, ay2/det2, az2/det2); + + // // std::cout << det << " " << det2 << std::endl; + // for (int ka=0; ka<3; ++ka) + // { + // double tmp = 0.0; + // for (kb=0; kb<3; ++kb) + // tmp += Mmat[ka][kb]*apex[kb]; + // std::cout << tmp << " " << bvec[ka] << std::endl; + // } + + double nom=0.0, denom=0.0; + for (size_t ki=0; ki<points.size(); ++ki) + { + vector<RevEngPoint*>::iterator start = points[ki].first; + vector<RevEngPoint*>::iterator end = points[ki].second; + for (auto it=start; it!=end; ++it) + { + RevEngPoint *pt = *it; + Vector3D xyz = pt->getPoint(); + Point pos(xyz[0], xyz[1], xyz[2]); + Point tmp1 = pos - apex; + Point tmp2 = tmp1.cross(axis); + nom += tmp2.length(); + denom += tmp1*axis; + } + } + + double tanphi = nom/denom; + phi = atan(tanphi); +} + +//=========================================================================== +void +RevEngUtils::computeSphereProp(vector<pair<vector<RevEngPoint*>::iterator, + vector<RevEngPoint*>::iterator> >& points, + Point& centre, double& radius) +//=========================================================================== +{ + double Amat[4][4]; + double bvec[4]; + // vector<vector<double> > Amat(4, vector<double>(4,0.0)); + // vector<double> bvec(4, 0.0); + size_t numpt = 0; + for (size_t ki=0; ki<points.size(); ++ki) + { + numpt += (points[ki].second - points[ki].first); + } + + vector<vector<double> > A1(numpt); + vector<double> b1(numpt); + for (size_t kj=0; kj<numpt; ++kj) + A1[kj].resize(4); + + for (int ka=0; ka<4; ++ka) + { + for (int kb=0; kb<4; ++kb) + Amat[ka][kb] = 0.0; + bvec[ka] = 0.0; + } + + double wgt = 1.0/(double)numpt; + for (size_t ki=0; ki<points.size(); ++ki) + { + vector<RevEngPoint*>::iterator start = points[ki].first; + vector<RevEngPoint*>::iterator end = points[ki].second; + size_t kj = 0; + for (auto it=start; it!=end; ++it, ++kj) + { + Vector3D curr = (*it)->getPoint(); + A1[kj][0] = 2*curr[0]; + A1[kj][1] = 2*curr[1]; + A1[kj][2] = 2*curr[2]; + A1[kj][3] = 1.0; + b1[kj] = curr.length2(); + } + } + + for (int ka=0; ka<4; ++ka) + { + for (int kb=0; kb<4; ++kb) + { + for (size_t kr=0; kr<numpt; ++kr) + Amat[ka][kb] += wgt*A1[kr][ka]*A1[kr][kb]; + } + for (size_t kr=0; kr<numpt; ++kr) + bvec[ka] += wgt*A1[kr][ka]*b1[kr]; + } + + // double detA = 0.0; + // double bx[3]; + // bx[0] = bx[1] = bx[2] = 0.0; + // int sgn1 = 1, sgn2 = 1; + // for (int kb=0; kb<4; ++kb, sgn1*=(-1)) + // { + // for (int kc=0; kc<4; ++kc) + // { + // if (kc == kb) + // continue; + // int ka1 = (kb == 0); + // int ka2 = 3 - (kb == 3); + // detA += sgn1*Amat[0][kb]* + // (sgn2*Amat[1][kc]*(Amat[2][ka1]*Amat[3][ka2]- + // Amat[3][ka1]*Amat[2][ka2])); + // bx[0] += sgn1*bvec[kb]* + // (sgn2*Amat[1][kc]*(Amat[2][ka1]*Amat[3][ka2]- + // Amat[3][ka1]*Amat[2][ka2])); + // bx[1] += sgn1*Amat[0][kb]* + // (sgn2*bvec[kc]*(Amat[2][ka1]*Amat[3][ka2]- + // Amat[3][ka1]*Amat[2][ka2])); + // bx[2] += sgn1*Amat[0][kv]* + // (sgn2*Amat[1][kc]*(bvec[ka1]Amat[3][ka2]- + // bvec[ka2]*Amat[3][ka1])); + // bx[3] += sgn1*Amat[0][kb]* + // sgn2*Amat[1][kc]*((Amat[2][ka1]*bvec[ka2]-Amat[1][ka2]*bvec[ka1]); + // sgn2 += -1; + // } + // } + // double sx = bx[0]/detA; + // double sy = bx[1]/detA; + // double sz = bx[2]/detA; + // double r2 = bx[3]/detA; + LUsolveSystem(Amat, 4, &bvec[0]); + double sx = bvec[0]; + double sy = bvec[1]; + double sz = bvec[2]; + double r2 = bvec[3]; + + centre = Point(sx,sy,sz); + + radius = (r2 + sx*sx + sy*sy + sz*sz < 0.0) ? 0.0 : sqrt(r2 + sx*sx + sy*sy + sz*sz); + } + +//=========================================================================== +void RevEngUtils::computeCylPosRadius(vector<pair<vector<RevEngPoint*>::iterator, + vector<RevEngPoint*>::iterator> >& points, + Point& low, Point& high, + Point& axis, Point& Cx, Point& Cy, + Point& pos, double& radius) +//=========================================================================== +{ + double Amat[3][3]; + double bvec[3]; + size_t numpt = 0; + for (size_t ki=0; ki<points.size(); ++ki) + { + numpt += (points[ki].second - points[ki].first); + } + Point mid = 0.5*(low+high); + + vector<vector<double> > A1(numpt); + vector<double> b1(numpt); + for (size_t kj=0; kj<numpt; ++kj) + A1[kj].resize(3); + + for (int ka=0; ka<3; ++ka) + { + for (int kb=0; kb<3; ++kb) + Amat[ka][kb] = 0.0; + bvec[ka] = 0.0; + } + + for (size_t ki=0; ki<points.size(); ++ki) + { + vector<RevEngPoint*>::iterator start = points[ki].first; + vector<RevEngPoint*>::iterator end = points[ki].second; + size_t kj = 0; + for (auto it=start; it!=end; ++it, ++kj) + { + Vector3D curr = (*it)->getPoint(); + Point curr2(curr[0], curr[1], curr[2]); + curr2 -= mid; + double pxy[3]; + double px = curr2*Cx; + double py = curr2*Cy; + pxy[0] = 2*px; + pxy[1] = 2*py; + pxy[2] = 1.0; + double plen2 = px*px + py*py; + A1[kj][0] = 2*px; + A1[kj][1] = 2*py; + A1[kj][2] = 1.0; + b1[kj] = plen2; + for (int ka=0; ka<3; ++ka) + { + for (int kb=0; kb<3; ++kb) + Amat[ka][kb] += pxy[ka]*pxy[kb]; + bvec[ka] += pxy[ka]*plen2; + } + } + } + + double Amat2[3][3]; + double bvec2[3]; + for (int ka=0; ka<3; ++ka) + { + for (int kb=0; kb<3; ++kb) + Amat2[ka][kb] = 0.0; + bvec2[ka] = 0.0; + } + for (int ka=0; ka<3; ++ka) + { + for (int kb=0; kb<3; ++kb) + { + for (size_t kr=0; kr<numpt; ++kr) + Amat2[ka][kb] += A1[kr][ka]*A1[kr][kb]; + } + for (size_t kr=0; kr<numpt; ++kr) + bvec2[ka] += A1[kr][ka]*b1[kr]; + } + + double detA = 0.0; + double bx[3]; + bx[0] = bx[1] = bx[2] = 0.0; + int sgn = 1; + for (int kb=0; kb<3; ++kb, sgn*=(-1)) + { + int ka1 = (kb == 0); + int ka2 = 2 - (kb == 2); + detA += sgn*Amat[0][kb]*(Amat[1][ka1]*Amat[2][ka2]-Amat[2][ka1]*Amat[1][ka2]); + bx[0] += sgn*bvec[kb]*(Amat[1][ka1]*Amat[2][ka2]-Amat[2][ka1]*Amat[1][ka2]); + bx[1] += sgn*Amat[0][kb]*(bvec[ka1]*Amat[2][ka2]-bvec[ka2]*Amat[2][ka1]); + bx[2] += sgn*Amat[0][kb]*(Amat[1][ka1]*bvec[ka2]-Amat[1][ka2]*bvec[ka1]); + } + double sx = bx[0]/detA; + double sy = bx[1]/detA; + double r2 = bx[2]/detA; + + Point pos2 = sx*Cx + sy*Cy; + pos2 += mid; + + radius = (r2 + sx*sx + sy*sy < 0.0) ? 0.0 : sqrt(r2 + sx*sx + sy*sy); + double len = low.dist(high); + Point vec = mid - pos2; + Point ax = axis; + ax.normalize(); + pos = pos2 + (vec*ax)*ax; + } + + + +//=========================================================================== +void RevEngUtils::computeCircPosRadius(vector<Point>& points, + const Point& axis, const Point& Cx, + const Point& Cy, Point& pos, double& radius) +//=========================================================================== +{ + double Amat[3][3]; + double bvec[3]; + size_t numpt = points.size(); + double wgt = 1.0/(double)numpt; + + vector<vector<double> > A1(numpt); + vector<double> b1(numpt); + for (size_t kj=0; kj<numpt; ++kj) + A1[kj].resize(3); + + for (int ka=0; ka<3; ++ka) + { + for (int kb=0; kb<3; ++kb) + Amat[ka][kb] = 0.0; + bvec[ka] = 0.0; + } + + Point mid(0.0, 0.0, 0.0); + for (size_t ki=0; ki<points.size(); ++ki) + mid += wgt*points[ki]; + + for (size_t ki=0; ki<points.size(); ++ki) + { + double pxy[3]; + double px = (points[ki]-mid)*Cx; + double py = (points[ki]-mid)*Cy; + pxy[0] = 2*px; + pxy[1] = 2*py; + pxy[2] = 1.0; + double plen2 = px*px + py*py; + A1[ki][0] = 2*px; + A1[ki][1] = 2*py; + A1[ki][2] = 1.0; + b1[ki] = plen2; + for (int ka=0; ka<3; ++ka) + { + for (int kb=0; kb<3; ++kb) + Amat[ka][kb] += pxy[ka]*pxy[kb]; + bvec[ka] += pxy[ka]*plen2; + } + } + + double Amat2[3][3]; + double bvec2[3]; + for (int ka=0; ka<3; ++ka) + { + for (int kb=0; kb<3; ++kb) + Amat2[ka][kb] = 0.0; + bvec2[ka] = 0.0; + } + for (int ka=0; ka<3; ++ka) + { + for (int kb=0; kb<3; ++kb) + { + for (size_t kr=0; kr<numpt; ++kr) + Amat2[ka][kb] += A1[kr][ka]*A1[kr][kb]; + } + for (size_t kr=0; kr<numpt; ++kr) + bvec2[ka] += A1[kr][ka]*b1[kr]; + } + + double detA = 0.0; + double bx[3]; + bx[0] = bx[1] = bx[2] = 0.0; + int sgn = 1; + for (int kb=0; kb<3; ++kb, sgn*=(-1)) + { + int ka1 = (kb == 0); + int ka2 = 2 - (kb == 2); + detA += sgn*Amat[0][kb]*(Amat[1][ka1]*Amat[2][ka2]-Amat[2][ka1]*Amat[1][ka2]); + bx[0] += sgn*bvec[kb]*(Amat[1][ka1]*Amat[2][ka2]-Amat[2][ka1]*Amat[1][ka2]); + bx[1] += sgn*Amat[0][kb]*(bvec[ka1]*Amat[2][ka2]-bvec[ka2]*Amat[2][ka1]); + bx[2] += sgn*Amat[0][kb]*(Amat[1][ka1]*bvec[ka2]-Amat[1][ka2]*bvec[ka1]); + } + if (fabs(detA) < 1.0e-12 || std::isnan(detA)) + THROW("Circle computation fail"); + //std::cout << "Circposradius, detA:" << detA << std::endl; + + double sx = bx[0]/detA; + double sy = bx[1]/detA; + double r2 = bx[2]/detA; + + pos = sx*Cx + sy*Cy; + pos += mid; + pos -= ((pos-mid)*axis)*axis; + + radius = (r2 + sx*sx + sy*sy < 0.0) ? 0.0 : sqrt(r2 + sx*sx + sy*sy); + } + + + +//=========================================================================== +void RevEngUtils::computeRadius(vector<Point>& points, Point& axis, + Point& Cx, Point& Cy, double& radius) +//=========================================================================== +{ + double Amat[3][3]; + double bvec[3]; + size_t numpt = points.size(); + double wgt = 1.0/numpt; + + vector<vector<double> > A1(numpt); + vector<double> b1(numpt); + for (size_t kj=0; kj<numpt; ++kj) + A1[kj].resize(3); + + for (int ka=0; ka<3; ++ka) + { + for (int kb=0; kb<3; ++kb) + Amat[ka][kb] = 0.0; + bvec[ka] = 0.0; + } + + Point mid(0.0, 0.0, 0.0); + for (size_t ki=0; ki<points.size(); ++ki) + mid += wgt*points[ki]; + + for (size_t ki=0; ki<points.size(); ++ki) + { + double pxy[3]; + double px = (points[ki]-mid)*Cx; + double py = (points[ki]-mid)*Cy; + pxy[0] = 2*px; + pxy[1] = 2*py; + pxy[2] = 1.0; + double plen2 = px*px + py*py; + A1[ki][0] = 2*px; + A1[ki][1] = 2*py; + A1[ki][2] = 1.0; + b1[ki] = plen2; + for (int ka=0; ka<3; ++ka) + { + for (int kb=0; kb<3; ++kb) + Amat[ka][kb] += pxy[ka]*pxy[kb]; + bvec[ka] += pxy[ka]*plen2; + } + } + + double Amat2[3][3]; + double bvec2[3]; + for (int ka=0; ka<3; ++ka) + { + for (int kb=0; kb<3; ++kb) + Amat2[ka][kb] = 0.0; + bvec2[ka] = 0.0; + } + for (int ka=0; ka<3; ++ka) + { + for (int kb=0; kb<3; ++kb) + { + for (size_t kr=0; kr<numpt; ++kr) + Amat2[ka][kb] += A1[kr][ka]*A1[kr][kb]; + } + for (size_t kr=0; kr<numpt; ++kr) + bvec2[ka] += A1[kr][ka]*b1[kr]; + } + + double detA = 0.0; + double bx[3]; + bx[0] = bx[1] = bx[2] = 0.0; + int sgn = 1; + for (int kb=0; kb<3; ++kb, sgn*=(-1)) + { + int ka1 = (kb == 0); + int ka2 = 2 - (kb == 2); + detA += sgn*Amat[0][kb]*(Amat[1][ka1]*Amat[2][ka2]-Amat[2][ka1]*Amat[1][ka2]); + bx[0] += sgn*bvec[kb]*(Amat[1][ka1]*Amat[2][ka2]-Amat[2][ka1]*Amat[1][ka2]); + bx[1] += sgn*Amat[0][kb]*(bvec[ka1]*Amat[2][ka2]-bvec[ka2]*Amat[2][ka1]); + bx[2] += sgn*Amat[0][kb]*(Amat[1][ka1]*bvec[ka2]-Amat[1][ka2]*bvec[ka1]); + } + if (fabs(detA) < 1.0e-12) + THROW("Circle with infinite radius"); + + double sx = bx[0]/detA; + double sy = bx[1]/detA; + double r2 = bx[2]/detA; + + radius = (r2 + sx*sx + sy*sy < 0.0) ? 0.0 : sqrt(r2 + sx*sx + sy*sy); + } + + +//=========================================================================== +void RevEngUtils::computePlane(vector<Point>& points, Point normal, + Point mainaxis[3], + Point& pos, Point& norm, Point& Cx, Point& Cy) +//=========================================================================== +{ + Point pos0(0.0, 0.0, 0.0); + double wgt = 1.0/(double)(points.size()); + for (size_t ki=0; ki<points.size(); ++ki) + pos0 += wgt*points[ki]; + + ImplicitApprox impl; + impl.approxPoints(points, 1); + bool found = impl.projectPoint(pos0, normal, pos, norm); + if (!found) + { + double eps = 1.0e-4; + double ang_min = 0.25*M_PI; + pos = pos0; + Point vec = points[0] - pos; + norm = Point(0.0, 0.0, 0.0); + size_t ki, kj; + for (ki=1; ki<points.size(); ++ki) + { + if (vec.length() > eps) + break; + vec = points[ki] - pos; + for (kj=ki+1; kj<points.size(); ++kj) + { + Point vec2 = points[kj] - pos; + double ang = vec.angle(vec2); + if (ang >= ang_min) + { + Point norm2 = vec.cross(vec2); + if (normal*norm2 < 0.0) + norm2 *= -1; + norm2.normalize(); + norm += norm2; + break; + } + } + } + norm.normalize(); + } + if (normal*norm < 0.0) + norm *= -1.0; + + // Define x-axis + int ix = -1; + double minang = M_PI; + for (int ka=0; ka<3; ++ka) + { + double ang = mainaxis[ka].angle(norm); + ang = std::min(ang, M_PI-ang); + if (ang < minang) + { + minang = ang; + ix = ka; + } + } + + Cy = mainaxis[(ix+1)%3].cross(norm); + Cx = norm.cross(Cy); +} + +//=========================================================================== +void RevEngUtils::computeLine(vector<Point>& points, Point& pos, Point& dir) +//=========================================================================== +{ + size_t num = points.size(); + pos = Point(0.0, 0.0, 0.0); + dir = Point(0.0, 0.0, 0.0); + if (num == 0) + return; + + double fac = 1.0/(double)num; + BoundingBox bb(3); + for (size_t ki=0; ki<num; ++ki) + { + pos += fac*points[ki]; + bb.addUnionWith(points[ki]); + } + + Point dir0 = bb.high() - bb.low(); + for (size_t ki=0; ki<num; ++ki) + { + Point tmp = points[ki] - pos; + (void)tmp.normalize_checked(); + if (tmp*dir0 < 0.0) + tmp *= -1; + dir += fac*tmp; + } + (void)dir.normalize_checked(); +} + +//=========================================================================== +void RevEngUtils::projectToPlane(vector<RevEngPoint*>& points, + Point& axis, Point& mid, std::vector<Point>& projected, + double& maxdist, double& avdist, double dlen) +//=========================================================================== +{ + vector<pair<vector<RevEngPoint*>::iterator, + vector<RevEngPoint*>::iterator> > points2; + points2.push_back(std::make_pair(points.begin(), points.end())); + projectToPlane(points2, axis, mid, projected, maxdist, avdist, dlen); +} + +//=========================================================================== +void RevEngUtils::projectToPlane(std::vector<std::pair<std::vector<RevEngPoint*>::iterator, + std::vector<RevEngPoint*>::iterator> >& points, + Point& axis, Point& mid, std::vector<Point>& projected, + double& maxdist, double& avdist, double dlen) +//=========================================================================== +{ + maxdist = 0.0; + avdist = 0.0; + int nmb = 0; + for (size_t ki=0; ki<points.size(); ++ki) + { + vector<RevEngPoint*>::iterator start = points[ki].first; + vector<RevEngPoint*>::iterator end = points[ki].second; + for (auto it=start; it!=end; ++it) + { + RevEngPoint *pt = *it; + Vector3D pnt = pt->getPoint(); + Point curr(pnt[0], pnt[1], pnt[2]); + Point curr2 = curr - mid; + double dd = curr2*axis; + if (dlen > 0.0 && dd > dlen) + continue; + curr2 -= (dd*axis); + curr2 += mid; + projected.push_back(curr2); + double dist = curr.dist(curr2); + maxdist = std::max(maxdist, dist); + avdist += dist; + nmb++; + } + } + avdist /= (double)nmb; +} + +//=========================================================================== +void RevEngUtils::rotateToPlane(vector<pair<vector<RevEngPoint*>::iterator, + vector<RevEngPoint*>::iterator> >& points, + Point& xvec, Point& axis, Point& mid, + vector<Point>& rotated) +//=========================================================================== +{ + Point yvec = xvec.cross(axis); + for (size_t ki=0; ki<points.size(); ++ki) + { + vector<RevEngPoint*>::iterator start = points[ki].first; + vector<RevEngPoint*>::iterator end = points[ki].second; + for (auto it=start; it!=end; ++it) + { + RevEngPoint *pt = *it; + Vector3D pnt = pt->getPoint(); + Point curr(pnt[0], pnt[1], pnt[2]); + curr -= mid; + pnt = Vector3D(curr[0], curr[1], curr[2]); + curr -= (curr*axis)*axis; + double angle = curr.angle(xvec); + if (curr*yvec < 0.0) + angle *= -1.0; + Matrix3D mat; + mat.setToRotation(angle, axis[0], axis[1], axis[2]); + Vector3D pnt2 = mat*pnt; + rotated.push_back(mid + Point(pnt2[0], pnt2[1], pnt2[2])); + } + } + } + +//=========================================================================== +void RevEngUtils::rotateToPlane(vector<Point>& points, + Point& xvec, Point& axis, Point& mid, + vector<Point>& rotated) +//=========================================================================== +{ + rotated.resize(points.size()); + Point yvec = xvec.cross(axis); + for (size_t ki=0; ki<points.size(); ++ki) + { + Point curr = points[ki]; + curr -= mid; + Vector3D pnt(curr[0], curr[1], curr[2]); + curr -= (curr*axis)*axis; + double angle = curr.angle(xvec); + if (curr*yvec < 0.0) + angle *= -1.0; + Matrix3D mat; + mat.setToRotation(angle, axis[0], axis[1], axis[2]); + Vector3D pnt2 = mat*pnt; + rotated[ki] = mid + Point(pnt2[0], pnt2[1], pnt2[2]); + } +} + +//=========================================================================== +void RevEngUtils::distToSurf(vector<RevEngPoint*>::iterator start, + vector<RevEngPoint*>::iterator end, + shared_ptr<ParamSurface> surf, double tol, + double& maxdist, double& avdist, + int& num_inside, int& num_inside2, + vector<RevEngPoint*>& in, vector<RevEngPoint*>& out, + vector<double>& parvals, + vector<pair<double,double> >& distang, + double angtol) +//=========================================================================== +{ + double eps = 1.0e-6; + maxdist = avdist = 0.0; + num_inside = num_inside2 = 0; + int num = (int)(end-start); + parvals.resize(2*num); + distang.resize(num); + in.clear(); + out.clear(); + double *seed = 0; + double seed2[2]; + Point prev; + double fac = 100.0; + double upar, vpar, dist; + Point close; + Point norm1, norm2, norm3; + double ang, ang2; + double dfac = 1.0/(double)num; + size_t ki=0; + for (auto it=start; it!=end; ++it, ++ki) + { + Vector3D xyz = (*it)->getPoint(); + Point pnt(xyz[0], xyz[1], xyz[2]); + if (prev.dimension() == pnt.dimension() && prev.dist(pnt) < fac*tol) + seed = seed2; + + surf->closestPoint(pnt, upar, vpar, close, dist, eps, 0, seed); + parvals[2*ki] = upar; + parvals[2*ki+1] = vpar; + surf->normal(norm1, upar, vpar); + norm2 = (*it)->getLocFuncNormal(); + norm3 = (*it)->getTriangNormal(); + maxdist = std::max(maxdist, dist); + avdist += dfac*dist; + ang = norm1.angle(norm2); + ang2 = norm1.angle(norm3); + ang = std::min(std::min(M_PI-ang, ang), std::min(M_PI-ang2,ang2)); + distang[ki] = std::make_pair(dist, ang); + if (dist <= tol) + { + ++num_inside2; + if (angtol < 0.0 || ang <= angtol) + { + in.push_back(*it); + ++num_inside; + } + else + out.push_back(*it); + } + else + out.push_back(*it); + seed2[0] = upar; + seed2[1] = vpar; + prev = pnt; + } +} + +//=========================================================================== +void RevEngUtils::distToSurf(vector<RevEngPoint*>::iterator start, + vector<RevEngPoint*>::iterator end, + shared_ptr<ParamSurface> surf, double tol, + double& maxdist, double& avdist, + int& num_inside, int& num_inside2, + vector<double>& parvals, + vector<pair<double,double> >& distang, + double angtol) +//=========================================================================== +{ + double eps = 1.0e-6; + maxdist = avdist = 0.0; + num_inside = num_inside2 = 0; + int num = (int)(end-start); + parvals.resize(2*num); + distang.resize(num); + double *seed = 0; + double seed2[2]; + Point prev; + double fac = 100.0; + double upar, vpar, dist; + Point close; + Point norm1, norm2, norm3; + double ang, ang2; + double dfac = 1.0/(double)num; + size_t ki=0; + for (auto it=start; it!=end; ++it, ++ki) + { + Vector3D xyz = (*it)->getPoint(); + Point pnt(xyz[0], xyz[1], xyz[2]); + if (prev.dimension() == pnt.dimension() && prev.dist(pnt) < fac*tol) + seed = seed2; + + surf->closestPoint(pnt, upar, vpar, close, dist, eps, 0, seed); + parvals[2*ki] = upar; + parvals[2*ki+1] = vpar; + surf->normal(norm1, upar, vpar); + norm2 = (*it)->getLocFuncNormal(); + norm3 = (*it)->getTriangNormal(); + maxdist = std::max(maxdist, dist); + avdist += dfac*dist; + ang = norm1.angle(norm2); + ang2 = norm1.angle(norm3); + ang = std::min(std::min(M_PI-ang, ang), std::min(M_PI-ang2,ang2)); + distang[ki] = std::make_pair(dist, ang); + if (dist <= tol) + { + ++num_inside2; + if (angtol < 0.0 || ang <= angtol) + ++num_inside; + } + seed2[0] = upar; + seed2[1] = vpar; + prev = pnt; + } +} + +//=========================================================================== +void RevEngUtils::distToSurf(vector<RevEngPoint*>& points, + shared_ptr<ParamSurface> surf, double tol, + double angtol, double& maxdist, double& avdist, + int& inside, int& inside2, + vector<pair<double,double> >& dist_ang) +//=========================================================================== +{ + double eps = 1.0e-6; + maxdist = avdist = 0.0; + inside = inside2 = 0; + int num = (int)points.size(); + dist_ang.resize(num); + double *seed = 0; + double seed2[2]; + Point prev; + double fac = 100.0; + double upar, vpar, dist; + Point close; + Point norm1, norm2, norm3; + double ang, ang2; + double dfac = 1.0/(double)num; + for (size_t ki=0; ki<points.size(); ++ki) + { + Vector3D xyz = points[ki]->getPoint(); + Point pnt(xyz[0], xyz[1], xyz[2]); + if (prev.dimension() == pnt.dimension() && prev.dist(pnt) < fac*tol) + seed = seed2; + + surf->closestPoint(pnt, upar, vpar, close, dist, eps, 0, seed); + surf->normal(norm1, upar, vpar); + norm2 = points[ki]->getLocFuncNormal(); + norm3 = points[ki]->getTriangNormal(); + maxdist = std::max(maxdist, dist); + avdist += dfac*dist; + ang = norm1.angle(norm2); + ang2 = norm1.angle(norm3); + ang = std::min(std::min(M_PI-ang, ang), std::min(M_PI-ang2,ang2)); + dist_ang[ki] = std::make_pair(dist, ang); + if (dist <= tol) + { + ++inside2; + if (angtol < 0.0 || ang <= angtol) + { + ++inside; + } + } + seed2[0] = upar; + seed2[1] = vpar; + prev = pnt; + } +} + +//=========================================================================== +void RevEngUtils::distToSurf(vector<Point>& points, + shared_ptr<ParamSurface> surf, double tol, + double& maxdist, double& avdist, int& num_inside, + vector<double>& distance) +//=========================================================================== +{ + double eps = 1.0e-6; + maxdist = avdist = 0.0; + num_inside = 0; + int num = (int)points.size(); + distance.resize(num); + double fac = 1.0/(double)num; + for (size_t ki=0; ki<points.size(); ++ki) + { + double upar, vpar, dist; + Point close; + surf->closestPoint(points[ki], upar, vpar, close, dist, eps); + maxdist = std::max(maxdist, dist); + avdist += fac*dist; + distance[ki] = dist; + if (dist <= tol) + ++num_inside; + else + { + int stop_break = 1; + } + } +} + +//=========================================================================== +void RevEngUtils::distToCurve(vector<Point>& points, + shared_ptr<ParamCurve> curve, double tol, + double& maxdist, double& avdist, int& num_inside) +//=========================================================================== +{ + double eps = 1.0e-6; + maxdist = avdist = 0.0; + num_inside = 0; + int num = (int)points.size(); + double fac = 1.0/(double)num; + for (size_t ki=0; ki<points.size(); ++ki) + { + double tpar, dist; + Point close; + curve->closestPoint(points[ki], curve->startparam(), curve->endparam(), + tpar, close, dist); + maxdist = std::max(maxdist, dist); + avdist += fac*dist; + if (dist <= tol) + ++num_inside; + else + { + int stop_break = 1; + } + } +} + + +//=========================================================================== +void RevEngUtils::distToCurve(vector<Point>& points, + shared_ptr<ParamCurve> curve, double tol, + double& maxdist, double& avdist, int& num_inside, + vector<double>& dist) +//=========================================================================== +{ + double eps = 1.0e-6; + maxdist = avdist = 0.0; + num_inside = 0; + int num = 0; + dist.resize(points.size()); + for (size_t ki=0; ki<points.size(); ++ki) + { + double tpar; + Point close; + curve->closestPoint(points[ki], curve->startparam(), curve->endparam(), + tpar, close, dist[ki]); + maxdist = std::max(maxdist, dist[ki]); + avdist += dist[ki]; + if (dist[ki] <= tol) + ++num_inside; + else + { + int stop_break = 1; + } + ++num; + } + avdist /= (double)num; +} + +//=========================================================================== +void RevEngUtils::distToCurve(vector<Point>& points, + shared_ptr<ParamCurve> curve, double tol, + double& maxdist, double& avdist, int& num_inside, + vector<double>& parvals, vector<double>& dist) +//=========================================================================== +{ + double eps = 1.0e-6; + maxdist = avdist = 0.0; + num_inside = 0; + int num = 0; + parvals.resize(points.size()); + dist.resize(points.size()); + for (size_t ki=0; ki<points.size(); ++ki) + { + double tpar; + Point close; + curve->closestPoint(points[ki], curve->startparam(), curve->endparam(), + parvals[ki], close, dist[ki]); + maxdist = std::max(maxdist, dist[ki]); + avdist += dist[ki]; + if (dist[ki] <= tol) + ++num_inside; + else + { + int stop_break = 1; + } + ++num; + } + avdist /= (double)num; +} + + +//=========================================================================== +shared_ptr<ElementarySurface> +RevEngUtils::elemsurfWithAxis(shared_ptr<ElementarySurface> sf_in, + vector<RevEngPoint*>& points, + Point mainaxis[3], double diag) +//=========================================================================== +{ + Point axis = sf_in->direction(); + Point loc = sf_in->location(); + Point Cx = sf_in->direction2(); + if (sf_in->instanceType() == Class_Plane) + return planeWithAxis(points, axis, loc, mainaxis); + else if (sf_in->instanceType() == Class_Cylinder) + return cylinderWithAxis(points, axis, Cx, loc); + else if (sf_in->instanceType() == Class_Torus) + return torusWithAxis(points, axis, Cx, loc); + else if (sf_in->instanceType() == Class_Sphere) + return sphereWithAxis(points, axis, Cx, loc); + else if (sf_in->instanceType() == Class_Cone) + return coneWithAxis(points, axis, Cx, loc, diag); + else + { + shared_ptr<ElementarySurface> dummy; + return dummy; + } +} + +//=========================================================================== +shared_ptr<Plane> RevEngUtils::planeWithAxis(vector<RevEngPoint*>& points, + Point axis, Point init_loc, + Point mainaxis[3]) +//=========================================================================== +{ + Point mid(0.0, 0.0, 0.0); + double wgt = 1.0/(double)points.size(); + for (size_t ki=0; ki<points.size(); ++ki) + { + Vector3D pos0 = points[ki]->getPoint(); + Point pos(pos0[0], pos0[1], pos0[2]); + Point vec = pos - init_loc; + Point pos2 = init_loc + (vec*axis)*axis; + mid += wgt*pos2; + } + + int ix=-1; + double min_ang = M_PI; + for (int ka=0; ka<3; ++ka) + { + double ang = axis.angle(mainaxis[ka]); + ang = std::min(ang, M_PI-ang); + if (ang < min_ang) + { + min_ang = ang; + ix = ka; + } + } + shared_ptr<Plane> plane(new Plane(mid, axis, mainaxis[(ix+1)%3])); + return plane; +} + +//=========================================================================== +shared_ptr<Cylinder> RevEngUtils::cylinderWithAxis(vector<RevEngPoint*>& points, + Point axis, Point low, + Point high, Point mainaxis[3]) +//=========================================================================== +{ + int ix=-1; + double min_ang = M_PI; + for (int ka=0; ka<3; ++ka) + { + double ang = axis.angle(mainaxis[ka]); + ang = std::min(ang, M_PI-ang); + if (ang < min_ang) + { + min_ang = ang; + ix = ka; + } + } + + Point Cx = mainaxis[(ix+2)%3].cross(axis); + Cx.normalize(); + Point Cy = axis.cross(Cx); + Cy.normalize(); + + Point pos; + double rad; + vector<pair<vector<RevEngPoint*>::iterator, + vector<RevEngPoint*>::iterator> > group; + group.push_back(std::make_pair(points.begin(), points.end())); + RevEngUtils::computeCylPosRadius(group, low, high, axis, Cx, Cy, pos, rad); + + shared_ptr<Cylinder> cyl(new Cylinder(rad, pos, axis, Cy)); + return cyl; +} + +//=========================================================================== +shared_ptr<Cylinder> RevEngUtils::cylinderWithAxis(vector<RevEngPoint*>& points, + Point axis, Point Cx, + Point pos) +//=========================================================================== +{ + // Compute radius + double rad = 0.0; + double fac = 1.0/(double)points.size(); + for (size_t ki=0; ki<points.size(); ++ki) + { + Vector3D xyz = points[ki]->getPoint(); + Point pnt(xyz[0], xyz[1], xyz[2]); + Point pnt2 = pos + ((pnt - pos)*axis)*axis; + double dd = pnt.dist(pnt2); + rad += fac*dd; + } + + shared_ptr<Cylinder> cyl(new Cylinder(rad, pos, axis, Cx)); + return cyl; +} + +//=========================================================================== +shared_ptr<Torus> RevEngUtils::torusWithAxis(vector<RevEngPoint*>& points, + Point axis, Point loc, + Point mainaxis[3]) +//=========================================================================== +{ + int ix=-1; + double min_ang = M_PI; + for (int ka=0; ka<3; ++ka) + { + double ang = axis.angle(mainaxis[ka]); + ang = std::min(ang, M_PI-ang); + if (ang < min_ang) + { + min_ang = ang; + ix = ka; + } + } + + Point Cx = mainaxis[(ix+2)%3].cross(axis); + Cx.normalize(); + Point Cy = axis.cross(Cx); + Cy.normalize(); + + vector<Point> rotated; + vector<pair<vector<RevEngPoint*>::iterator, + vector<RevEngPoint*>::iterator> > group; + group.push_back(std::make_pair(points.begin(), points.end())); + rotateToPlane(group, Cy, axis, loc, rotated); + + // Approximate rotated points with a circle + Point centre; + double radius; + computeCircPosRadius(rotated, Cx, Cy, axis, centre, radius); + + Point axis_pt = loc + ((centre - loc)*axis)*axis; + double dist = centre.dist(axis_pt); + shared_ptr<Torus> torus(new Torus(dist, radius, axis_pt, axis, Cx)); + + return torus; + } + +//=========================================================================== +shared_ptr<Torus> RevEngUtils::torusWithAxis(vector<RevEngPoint*>& points, + Point axis, Point Cx, Point pos) +//=========================================================================== +{ + vector<Point> rotated; + vector<pair<vector<RevEngPoint*>::iterator, + vector<RevEngPoint*>::iterator> > group; + group.push_back(std::make_pair(points.begin(), points.end())); + Point Cy = axis.cross(Cx); + rotateToPlane(group, Cy, axis, pos, rotated); + + // Approximate rotated points with a circle + Point centre; + double radius; + computeCircPosRadius(rotated, Cx, Cy, axis, centre, radius); + + Point axis_pt = pos + ((centre - pos)*axis)*axis; + double dist = centre.dist(axis_pt); + shared_ptr<Torus> torus(new Torus(dist, radius, axis_pt, axis, Cx)); + + return torus; + } + +//=========================================================================== +shared_ptr<Sphere> RevEngUtils::sphereWithAxis(vector<RevEngPoint*>& points, + Point axis, + Point mainaxis[3]) +//=========================================================================== +{ + vector<pair<vector<RevEngPoint*>::iterator, + vector<RevEngPoint*>::iterator> > group; + group.push_back(std::make_pair(points.begin(), points.end())); + Point centre; + double radius; + try { + computeSphereProp(group, centre, radius); + } + catch (...) + { + shared_ptr<Sphere> dummy; + return dummy; + } + + // Define x-axis + int ix = -1; + double minang = M_PI; + for (int ka=0; ka<3; ++ka) + { + double ang = mainaxis[ka].angle(axis); + ang = std::min(ang, M_PI-ang); + if (ang < minang) + { + minang = ang; + ix = ka; + } + } + + Point Cy = mainaxis[(ix+1)%3].cross(axis); + Point Cx = axis.cross(Cy); + + shared_ptr<Sphere> sph(new Sphere(radius, centre, axis, Cx)); + return sph; +} + +//=========================================================================== +shared_ptr<Sphere> RevEngUtils::sphereWithAxis(vector<RevEngPoint*>& points, + Point axis, Point Cx, + Point pos) +//=========================================================================== +{ + // Compute radius + double rad = 0.0; + double fac = 1.0/(double)points.size(); + for (size_t ki=0; ki<points.size(); ++ki) + { + Vector3D xyz = points[ki]->getPoint(); + Point pnt(xyz[0], xyz[1], xyz[2]); + double dd = pnt.dist(pos); + rad += fac*dd; + } + + shared_ptr<Sphere> sph(new Sphere(rad, pos, axis, Cx)); + return sph; +} + +//=========================================================================== +shared_ptr<Cone> RevEngUtils::coneWithAxis(vector<RevEngPoint*>& points, + Point axis, Point low, + Point high, Point mainaxis[3]) +//=========================================================================== +{ + shared_ptr<Cylinder> cyl = + RevEngUtils::cylinderWithAxis(points, axis, low, high, mainaxis); + Point pnt = cyl->location(); + Point Cx, Cy, Cz; + cyl->getCoordinateAxes(Cx, Cy, Cz); + //double rad = cyl->getRadius(); + +#ifdef DEBUG_CONE + std::ofstream of("pts_cone.g2"); + of << "400 1 0 4 255 0 0 255" << std::endl; + of << points.size() << std::endl; + for (size_t ki=0; ki<points.size(); ++ki) + of << points[ki]->getPoint() << std::endl; +#endif + vector<Point> rotated; + vector<pair<vector<RevEngPoint*>::iterator, + vector<RevEngPoint*>::iterator> > group; + group.push_back(std::make_pair(points.begin(), points.end())); + RevEngUtils::rotateToPlane(group, Cy, axis, pnt, rotated); + + double len = low.dist(high); + shared_ptr<Line> line(new Line(pnt, axis)); + line->setParameterInterval(-len, len); + + Point pt1 = line->ParamCurve::point(-len); + Point pt2 = line->ParamCurve::point(len); + shared_ptr<SplineCurve> line_cv(new SplineCurve(pt1, -len, pt2, len)); + shared_ptr<SplineCurve> cv1; + curveApprox(rotated, line_cv, 2, 2, cv1); + + double tclose, dclose; + Point ptclose; + cv1->closestPoint(pnt, cv1->startparam(), cv1->endparam(), tclose, + ptclose, dclose); + vector<Point> der(2); + cv1->point(der, tclose, 1); + double phi = der[1].angle(axis); + shared_ptr<Cone> cone(new Cone(dclose, pnt, axis, Cy, phi)); + +#ifdef DEBUG_CONE + cone->writeStandardHeader(of); + cone->write(of); +#endif + return cone; +} + +//=========================================================================== +shared_ptr<Cone> RevEngUtils::coneWithAxis(vector<RevEngPoint*>& points, + Point axis, Point Cx, Point pos, + double len) +//=========================================================================== +{ +#ifdef DEBUG_CONE + std::ofstream of("pts_cone.g2"); + of << "400 1 0 4 255 0 0 255" << std::endl; + of << points.size() << std::endl; + for (size_t ki=0; ki<points.size(); ++ki) + of << points[ki]->getPoint() << std::endl; +#endif + + vector<Point> rotated; + vector<pair<vector<RevEngPoint*>::iterator, + vector<RevEngPoint*>::iterator> > group; + group.push_back(std::make_pair(points.begin(), points.end())); + RevEngUtils::rotateToPlane(group, Cx, axis, pos, rotated); + + shared_ptr<Line> line(new Line(pos, axis)); + line->setParameterInterval(-len, len); + + Point pt1 = line->ParamCurve::point(-len); + Point pt2 = line->ParamCurve::point(len); + shared_ptr<SplineCurve> line_cv(new SplineCurve(pt1, -len, pt2, len)); + shared_ptr<SplineCurve> cv1; + curveApprox(rotated, line_cv, 2, 2, cv1); +#ifdef DEBUG_CONE + cv1->writeStandardHeader(of); + cv1->write(of); +#endif + + // Expects one intersection point with plane through point-on-axis + shared_ptr<Cone> cone; + double eps = 1.0e-6; + vector<double> intpar; + vector<pair<double,double> > intcvs; + double tpar; + intersectCurvePlane(cv1.get(), pos, axis, eps, intpar, intcvs); + if (intpar.size() > 0) + tpar = intpar[0]; + else if (intcvs.size() > 0) + tpar = 0.5*(intcvs[0].first + intcvs[0].second); + else + return cone; + + vector<Point> der(2); + cv1->point(der, tpar, 1); + double phi = der[1].angle(axis); + double rad = der[0].dist(pos); + cone = shared_ptr<Cone>(new Cone(rad, pos, axis, Cx, phi)); + +#ifdef DEBUG_CONE + if (cone.get()) + { + cone->writeStandardHeader(of); + cone->write(of); + } +#endif + return cone; +} + +//=========================================================================== +shared_ptr<ParamSurface> RevEngUtils::doMergePlanes(vector<pair<vector<RevEngPoint*>::iterator, + vector<RevEngPoint*>::iterator> > points, + const BoundingBox& bbox, + vector<int>& nmbpts, + bool set_bound) +//=========================================================================== +{ + int totnmb = 0; + for (size_t kh=0; kh<nmbpts.size(); ++kh) + totnmb += nmbpts[kh]; + + Point pos(0.0, 0.0, 0.0); + Point norm(0.0, 0.0, 0.0); + vector<RevEngPoint*> all_pts; + all_pts.reserve(totnmb); + for (size_t ki=0; ki<points.size(); ++ki) + { + double wgt = 1.0/(double)totnmb; + + for (auto it=points[ki].first; it!=points[ki].second; ++it) + { + Point curr = (*it)->getLocFuncNormal(); + Vector3D xyz = (*it)->getPoint(); + pos += wgt*Point(xyz[0], xyz[1], xyz[2]); + norm += wgt*curr; + all_pts.push_back(*it); + } + } + + // Perform approximation with combined point set + ImplicitApprox impl; + impl.approx(points, 1); + Point pos2, normal2; + bool found = impl.projectPoint(pos, norm, pos2, normal2); + if (!found) + { + pos2 = pos; + normal2 = norm; + normal2.normalize(); + } + // std::ofstream outviz("implsf_merge.g2"); + // impl->visualize(all_pts, outviz); + + shared_ptr<Plane> surf(new Plane(pos2, normal2)); + Point low = bbox.low(); + Point high = bbox.high(); + if (set_bound) + { + double len = low.dist(high); + surf->setParameterBounds(-0.5*len, -0.5*len, 0.5*len, 0.5*len); + } + + return surf; +} + +//=========================================================================== +shared_ptr<ParamSurface> RevEngUtils::doMergeCylinders(vector<pair<vector<RevEngPoint*>::iterator, + vector<RevEngPoint*>::iterator> > points, + const BoundingBox& bbox, + vector<int>& nmbpts, + bool set_bound) +//=========================================================================== +{ + // Estimate cylinder axis + Point axis, Cx, Cy; + RevEngUtils::computeAxis(points, axis, Cx, Cy); + + // Estimate radius and point on axis + double rad; + Point pnt; + Point low = bbox.low(); + Point high = bbox.high(); + RevEngUtils::computeCylPosRadius(points, low, high, + axis, Cx, Cy, pnt, rad); + shared_ptr<Cylinder> surf(new Cylinder(rad, pnt, axis, Cy)); + if (set_bound) + { + double len = low.dist(high); + surf->setParamBoundsV(-len, len); + } + + return surf; +} + +//=========================================================================== +shared_ptr<ParamSurface> RevEngUtils::doMergeSpheres(vector<pair<vector<RevEngPoint*>::iterator, + vector<RevEngPoint*>::iterator> > points, + const BoundingBox& bbox, + vector<int>& nmbpts, Point& normal) +//=========================================================================== +{ + Point centre; + double radius; + try { + RevEngUtils::computeSphereProp(points, centre, radius); + } + catch (...) + { + shared_ptr<Sphere> dummy; + return dummy; + } + + int totnmb = 0; + for (size_t kh=0; kh<nmbpts.size(); ++kh) + totnmb += nmbpts[kh]; + vector<Point> pnts; + pnts.reserve(totnmb); + for (size_t ki=0; ki<points.size(); ++ki) + for (auto it=points[ki].first; it!=points[ki].second; ++it) + { + Vector3D xyz = (*it)->getPoint(); + pnts.push_back(Point(xyz[0], xyz[1], xyz[2])); + } + + double eigenvec[3][3]; + double lambda[3]; + Point eigen1, eigen2, eigen3; + RevEngUtils::principalAnalysis(pnts[0], pnts, lambda, eigenvec); + Point z_axis = Point(eigenvec[1][0], eigenvec[1][1], eigenvec[1][2]); + Point x_axis = normal.cross(z_axis); + + shared_ptr<Sphere> sph(new Sphere(radius, centre, z_axis, normal)); + + return sph; +} + +//=========================================================================== +shared_ptr<ParamSurface> RevEngUtils::doMergeTorus(vector<pair<vector<RevEngPoint*>::iterator, + vector<RevEngPoint*>::iterator> > points, + const BoundingBox& bbox, + vector<int>& nmbpts) +//=========================================================================== +{ + shared_ptr<ParamSurface> dummy; + + int totnmb = 0; + for (size_t kh=0; kh<nmbpts.size(); ++kh) + totnmb += nmbpts[kh]; + + // Compute mean curvature and initial point in plane + double k2mean = 0.0; + double wgt = 1.0/(double)totnmb; + for (size_t ki=0; ki<points.size(); ++ki) + { + for (auto it=points[ki].first; it!=points[ki].second; ++it) + { + double kmax = (*it)->maxPrincipalCurvature(); + k2mean += wgt*kmax; + } + } + double rd = 1.0/k2mean; + + vector<Point> centr(totnmb); + Point mid(0.0, 0.0, 0.0); + size_t kr = 0; + for (size_t ki=0; ki<points.size(); ++ki) + { + for (auto it=points[ki].first; it!=points[ki].second; ++it, ++kr) + { + Point norm = (*it)->getLocFuncNormal(); + Vector3D xyz = (*it)->getPoint(); + Point xyz2(xyz[0], xyz[1], xyz[2]); + centr[kr] = xyz2 + rd*norm; + mid += wgt*centr[kr]; + } + } + + ImplicitApprox impl; + impl.approxPoints(centr, 1); + + double val; + Point grad; + impl.evaluate(mid, val, grad); + grad.normalize_checked(); + Point pos, normal; + bool found = impl.projectPoint(mid, grad, pos, normal); + if (!found) + return dummy; + double eps1 = 1.0e-8; + if (normal.length() < eps1) + return dummy; + + Point Cx = centr[0] - mid; + Cx -= (Cx*normal)*normal; + Cx.normalize(); + Point Cy = Cx.cross(normal); + + double rad; + Point pnt; + RevEngUtils::computeCircPosRadius(centr, normal, Cx, Cy, pnt, rad); + pnt -= ((pnt - pos)*normal)*normal; + + vector<Point> rotated; + RevEngUtils::rotateToPlane(points, Cx, normal, pnt, rotated); + Point cpos; + double crad; + RevEngUtils::computeCircPosRadius(rotated, Cy, Cx, normal, cpos, crad); + Point cvec = cpos - pnt; + double R1 = (cvec - (cvec*normal)*normal).length(); + double R2 = (cvec*normal)*normal.length(); + + shared_ptr<Torus> surf(new Torus(R1, crad, pnt+R2*normal, normal, Cy)); + + return surf; +} + + +//=========================================================================== +shared_ptr<SplineCurve> RevEngUtils::midCurve(shared_ptr<SplineCurve>& cv1, + shared_ptr<SplineCurve>& cv2) +//=========================================================================== +{ + shared_ptr<SplineCurve> spl1(cv1->clone()); + shared_ptr<SplineCurve> spl2(cv2->clone()); + + // Check orientation + Point pt1 = spl1->ParamCurve::point(spl1->startparam()); + Point pt2 = spl1->ParamCurve::point(spl1->endparam()); + Point pt3 = spl2->ParamCurve::point(spl2->startparam()); + Point pt4 = spl2->ParamCurve::point(spl2->endparam()); + double len1 = pt1.dist(pt3); + double len2 = pt1.dist(pt4); + if (len2 < len1) + spl2->reverseParameterDirection(); + + // Ensure same spline room + spl2->setParameterInterval(spl1->startparam(), spl1->endparam()); + + double tol = 1.0e-4; + vector<shared_ptr<SplineCurve> > curves(2); + curves[0] = spl1; + curves[1] = spl2; + GeometryTools::unifyCurveSplineSpace(curves, tol); + + shared_ptr<SplineCurve> midcv = GeometryTools::curveSum(*curves[0], 0.5, + *curves[1], 0.5); + return midcv; +} + + +//=========================================================================== +void RevEngUtils::curveApprox(vector<Point>& points, + shared_ptr<ParamCurve> cvin, + int ik, int in, + shared_ptr<SplineCurve>& curve) +//=========================================================================== +{ + vector<double> pts; + vector<double> param; + double tmin = cvin->startparam(); + double tmax = cvin->endparam(); + double tmin2 = tmax; + double tmax2 = tmin; + for (size_t ki=0; ki<points.size(); ++ki) + { + double tpar, dist; + Point close; + cvin->closestPoint(points[ki], tmin, tmax, tpar, close, dist); + pts.insert(pts.end(), points[ki].begin(), points[ki].end()); + param.push_back(tpar); + tmin2 = std::min(tmin2, tpar); + tmax2 = std::max(tmax2, tpar); + } + + double tdel = (tmax2 - tmin2)/(double)(in - ik + 1); + vector<double> et(ik+in); + for (int ka=0; ka<ik; ++ka) + { + et[ka] = tmin2; + et[in+ka] = tmax2; + } + for (int ka=ik; ka<in; ++ka) + et[ka] = tmin2 + (ka-ik+1)*tdel; + + vector<double> ecoef(3*in, 0.0); + shared_ptr<SplineCurve> cv(new SplineCurve(in, ik, &et[0], &ecoef[0], 3)); + + SmoothCurve smooth(3); + vector<int> cfn(in, 0); + vector<double> wgts(param.size(), 1.0); + smooth.attach(cv, &cfn[0]); + + smooth.setOptim(0.0, 0.001, 0.001); + smooth.setLeastSquares(pts, param, wgts, 0.998); + + smooth.equationSolve(curve); + int stop_break = 1; +} + +//=========================================================================== +void RevEngUtils::curveApprox(vector<Point>& points, + vector<double>& param, + int ik, int in, + shared_ptr<SplineCurve>& curve) +//=========================================================================== +{ + if (points.size() == 0) + return; + if (points.size() != param.size()) + return; + vector<double> pts; + double tmin = std::numeric_limits<double>::max(); + double tmax = std::numeric_limits<double>::lowest(); + for (size_t ki=0; ki<points.size(); ++ki) + { + pts.insert(pts.end(), points[ki].begin(), points[ki].end()); + tmin = std::min(tmin, param[ki]); + tmax = std::max(tmax, param[ki]); + } + + double tdel = (tmax - tmin)/(double)(in - ik + 1); + vector<double> et(ik+in); + for (int ka=0; ka<ik; ++ka) + { + et[ka] = tmin; + et[in+ka] = tmax; + } + for (int ka=ik; ka<in; ++ka) + et[ka] = tmin + (ka-ik+1)*tdel; + + vector<double> ecoef(3*in, 0.0); + shared_ptr<SplineCurve> cv(new SplineCurve(in, ik, &et[0], &ecoef[0], 3)); + + SmoothCurve smooth(3); + vector<int> cfn(in, 0); + vector<double> wgts(param.size(), 1.0); + smooth.attach(cv, &cfn[0]); + + smooth.setOptim(0.0, 0.001, 0.001); + smooth.setLeastSquares(pts, param, wgts, 0.998); + + smooth.equationSolve(curve); + int stop_break = 1; +} + +//=========================================================================== +shared_ptr<SplineCurve> RevEngUtils::createCurve(vector<RevEngPoint*>& points, + int degree, double tol, int maxiter) +//=========================================================================== +{ + shared_ptr<SplineCurve> cv; + if (points.size() < 2) + return cv; + + // Parameterize curves and fetch data points + vector<double> param(points.size(), 0.0); + vector<double> pts; + pts.reserve(3*points.size()); + Vector3D prev = points[0]->getPoint(); + double tmp = 0.0; + for (size_t ki=0; ki<points.size(); ++ki) + { + Vector3D xyz = points[ki]->getPoint(); + pts.insert(pts.end(), xyz.begin(), xyz.end()); + param[ki] = tmp + prev.dist(xyz); + prev = xyz; + tmp = param[ki]; + } + + double smoothwgt = 0.1; + ApproxCurve approx(pts, param, 3, tol, degree+1, degree+1); + approx.setSmooth(smoothwgt); + + double maxdist, avdist; + cv = approx.getApproxCurve(maxdist, avdist, maxiter); + + return cv; +} + +//=========================================================================== +void RevEngUtils::extractLinearPoints(vector<RevEngPoint*>& points, + vector<Point>& rotated, double len, + Point& pos, Point& axis, double rad, + Point& axis2, bool plane, + double tol, double angtol, + vector<pair<double,double> >& dist_ang, + vector<RevEngPoint*>& linear, bool start, + vector<RevEngPoint*>& remaining) +//=========================================================================== +{ + // Parametarize the points according to axis + vector<double> param(points.size()); + vector<double> distance(points.size()); + vector<int> perm(points.size()); + shared_ptr<Line> line(new Line(pos, axis)); + line->setParameterInterval(-len, len); + + double tmin = -len; + double tmax = len; + for (size_t ki=0; ki<points.size(); ++ki) + { + double tpar, dist; + Point close; + line->closestPoint(rotated[ki], -len, len, tpar, close, dist); + param[ki] = tpar; + distance[ki] = dist; + perm[ki] = (int)ki; + tmin = std::min(tmin, tpar); + tmax = std::max(tmax, tpar); + } + + // Sort + for (size_t ki=0; ki<perm.size(); ++ki) + for (size_t kj=ki+1; kj<perm.size(); ++kj) + if (param[perm[kj]] < param[perm[ki]]) + std::swap(perm[ki], perm[kj]); + + // Identify linear points + double pihalf = 0.5*M_PI; + int ix1 = (start) ? 0 : (int)perm.size()-1; + int ix2 = (start) ? (int)perm.size() : -1; + int sgn = (start) ? 1 : -1; + int lim1 = std::min(10, (int)points.size()/200); + int lim2 = std::min(100, (int)points.size()/50); + int ka, kb; + int num_out = 0; + double fac = 0.9; + double dfac = 0.5; + for (ka=ix1; ka!=ix2; ka=kb) + { + Point norm = points[perm[ka]]->getLocFuncNormal(); + Point norm2 = points[perm[ka]]->getTriangNormal(); + double ang = norm.angle(axis2); + double ang2 = norm2.angle(axis2); + if (plane) + ang = std::min(std::min(ang,M_PI-ang), std::min(ang2,M_PI-ang2)); + else + ang = std::min(fabs(pihalf-ang), fabs(pihalf-ang2)); + double dd = fabs(distance[perm[ka]]-rad); + double anglim = (dist_ang.size() > 0) ? dist_ang[perm[ka]].second : 0.0; + double angtol2 = std::max(fac*anglim, angtol); + double tol2 = (dist_ang.size() > 0) ? + std::max(tol, dfac*dist_ang[perm[ka]].first) : tol;; + if (dd <= tol2 && ang <= angtol2) + kb = ka+sgn; + else + { + num_out++; + for (kb=ka+sgn; kb!=ix2; kb+=sgn) + { + norm = points[perm[kb]]->getLocFuncNormal(); + norm2 = points[perm[kb]]->getTriangNormal(); + ang = norm.angle(axis2); + ang2 = norm2.angle(axis2); + ang = std::min(fabs(pihalf-ang), fabs(pihalf-ang2)); + dd = fabs(distance[perm[kb]]-rad); + anglim = (dist_ang.size() > 0) ? dist_ang[perm[kb]].second : 0.0; + angtol2 = std::max(fac*anglim, angtol); + tol2 = (dist_ang.size() > 0) ? + std::max(tol, dfac*dist_ang[perm[kb]].first) : tol;; + if (dd <= tol2 && ang <= angtol2) + break; + num_out++; + if (abs(kb-ka) > lim1 || num_out > lim2) + break; + } + } + if (abs(kb-ka) > lim1 || num_out > lim2) + break; + } + + // Extract linear points + if (ka == ix2) + ka+=sgn; + for (kb=ix1; kb!=ka && kb<(int)perm.size() && kb>=0; kb+=sgn) + linear.push_back(points[perm[kb]]); + for (; kb!=ix2 && kb<(int)perm.size() && kb>=0; kb+=sgn) + remaining.push_back(points[perm[kb]]); + int stop_break = 1; +} + +struct LinInfo +{ + double t1_, t2_; + double mind_, maxd_, avd_, avd2_; + int nmb_; + + LinInfo() + { + t1_ = t2_ = mind_ = maxd_ = avd_ = avd2_ = 0.0; + nmb_ = 0; + } + + LinInfo(double t1, double t2, int nmb, double mind, double maxd, + double avd, double avd2) + { + t1_ = t1; + t2_ = t2; + nmb_ = nmb; + mind_ = mind; + maxd_ = maxd; + avd_ = avd; + avd2_ = avd2; + } +}; + +//=========================================================================== +bool RevEngUtils::extractLinearPoints(vector<Point>& points, + shared_ptr<Line>& line, Point norm, + double tol, bool start, double& splitpar, + vector<Point>& linear, + vector<Point>& remaining) +//=========================================================================== +{ + // Parametarize the points according to axis + vector<double> param(points.size()); + vector<double> distance(points.size()); + vector<int> perm(points.size()); + + double tmin = line->startparam(); + double tmax = line->endparam(); + for (size_t ki=0; ki<points.size(); ++ki) + { + double tpar, dist; + Point close; + line->closestPoint(points[ki], line->startparam(), line->endparam(), + tpar, close, dist); + param[ki] = tpar; + int sgn = ((close-points[ki])*norm > 0.0) ? 1 : -1; + distance[ki] = sgn*dist; + perm[ki] = (int)ki; + tmin = std::min(tmin, tpar); + tmax = std::max(tmax, tpar); + } + + // Sort + for (size_t ki=0; ki<perm.size(); ++ki) + for (size_t kj=ki+1; kj<perm.size(); ++kj) + if (param[perm[kj]] < param[perm[ki]]) + std::swap(perm[ki], perm[kj]); + + int ndiv = 100; + double tdel = (tmax - tmin)/(double)ndiv; + vector<LinInfo> info(ndiv); + double t1, t2; + int ka; + size_t kj=0; + for (ka=0, t1=tmin, t2=t1+tdel; ka<ndiv; ++ka, t1+=tdel, t2+=tdel) + { + int nmb = 0; + double maxd = std::numeric_limits<double>::lowest(); + double mind = std::numeric_limits<double>::max(); + double avd = 0.0, avd2 = 0.0; + for (; kj<perm.size() && param[perm[kj]] <= t2; ++kj) + { + avd += fabs(distance[perm[kj]]); + avd2 += distance[perm[kj]]; + maxd = std::max(maxd, distance[perm[kj]]); + mind = std::min(mind, distance[perm[kj]]); + ++nmb; + } + if (nmb > 0) + { + avd /= (double)nmb; + avd2 /= (double)nmb; + } + else + { + mind = maxd = avd = avd2 = 0.0; + } + LinInfo curr_info(t1, t2, nmb, mind, maxd, avd, avd2); + info[ka] = curr_info; + } + + // Count number of information entities without any points + int num_zero = 0; + for (size_t ki=0; ki<info.size(); ++ki) + if (info[ki].nmb_ == 0) + num_zero++; + + int zero_lim = ndiv/3; + if (num_zero > zero_lim) + return false; + + vector<double> par; + vector<double> range; + vector<double> avdist1; + vector<double> avdist2; + for (int ka=0; ka<ndiv; ++ka) + { + if (info[ka].nmb_ > 0) + { + par.push_back(0.5*(info[ka].t1_ + info[ka].t2_)); + range.push_back(info[ka].maxd_ - info[ka].mind_); + avdist1.push_back(info[ka].avd_); + avdist2.push_back(info[ka].avd2_); + } + } + + int in = 6; + int ik = 4; + double smoothwgt = 1.0e-5; + int maxiter = 4; + double tol2 = 1.0e-6; + double maxdist, avdist; + ApproxCurve approx2(avdist1, par, 1, tol2, in, ik); + shared_ptr<SplineCurve> cv2 = approx2.getApproxCurve(maxdist, avdist, maxiter); +#ifdef DEBUG_BLEND + double maxdistd, avdistd; + ApproxCurve approx1(range, par, 1, tol2, in, ik); + shared_ptr<SplineCurve> cv1 = approx1.getApproxCurve(maxdistd, avdistd, maxiter); + ApproxCurve approx3(avdist2, par, 1, tol2, in, ik); + shared_ptr<SplineCurve> cv3 = approx3.getApproxCurve(maxdistd, avdistd, maxiter); + std::ofstream of("dist_cvs.g2"); + SplineDebugUtils::writeSpace1DCurve(*cv1, of); + SplineDebugUtils::writeSpace1DCurve(*cv2, of); + SplineDebugUtils::writeSpace1DCurve(*cv3, of); + of << "410 1 0 0" << std::endl; + of << "1" << std::endl; + of << tmin << " 0 0 " << tmax << " 0 0 " << std::endl; + of << "410 1 0 0" << std::endl; + of << "1" << std::endl; + of << tmin << " " << tol << " 0 " << tmax << " " << tol << " 0 " << std::endl; + of << "410 1 0 0" << std::endl; + of << "1" << std::endl; + of << tmin << " " << 2*tol << " 0 " << tmax << " " << 2*tol << " 0 " << std::endl; + of << "410 1 0 0" << std::endl; + of << "1" << std::endl; + of << tmin << " " << -tol << " 0 " << tmax << " " << -tol << " 0 " << std::endl; + + shared_ptr<SplineCurve> cv1_2(cv1->derivCurve(1)); + shared_ptr<SplineCurve> cv2_2(cv2->derivCurve(1)); + shared_ptr<SplineCurve> cv3_2(cv3->derivCurve(1)); + + Point zero(1); + zero[0] = 0.0; + vector<double> intpar1, intpar2, intpar3; + vector<pair<double,double> > intcv1, intcv2, intcv3; + intersectCurvePoint(cv1_2.get(), zero, tol2, intpar1, intcv1); + intersectCurvePoint(cv2_2.get(), zero, tol2, intpar2, intcv2); + intersectCurvePoint(cv3_2.get(), zero, tol2, intpar3, intcv3); + for (auto it=cv1_2->coefs_begin(); it != cv1_2->coefs_end(); ++it) + (*it) *= 0.01; + for (auto it=cv2_2->coefs_begin(); it != cv2_2->coefs_end(); ++it) + (*it) *= 0.01; + for (auto it=cv3_2->coefs_begin(); it != cv3_2->coefs_end(); ++it) + (*it) *= 0.01; + std::ofstream of2("dist_cvs_2.g2"); + SplineDebugUtils::writeSpace1DCurve(*cv1_2, of2); + SplineDebugUtils::writeSpace1DCurve(*cv2_2, of2); + SplineDebugUtils::writeSpace1DCurve(*cv3_2, of2); +#endif + // Set limitation of average distance for the line to be an accepted + // approximation + int asgn = (start) ? 1 : -1; + double av1 = 0.0, minav2=2.0*tol, maxav2=0.0; + int an = 0; + double afac = 2.0; + for (int ka=(start)?0:ndiv-1; ka!=ndiv/2; ka+=asgn) + { + double av2=0.0; + double fac = 0.1; + for (int kb=0; kb<10; ++kb) + av2 += fac*info[ka+asgn*kb].avd_; + + if (an>0 && av2>afac*av1/(double)an) + break; + av1 += av2; + ++an; + minav2 = std::min(minav2, av2); + maxav2 = std::max(maxav2, av2); + } + if (an > 0) + av1 /= (double)an; + double av2del = maxav2 - minav2; + av2del = std::max(av2del, avdist); + + splitpar = (start) ? tmin - tmax : 2*tmax; + vector<double> intpar, intpar_n; + vector<pair<double,double> > intcv, intcv_n; + Point tolpt(1); + double tolfac = 3; + double toldel = tolfac*av2del; + toldel = std::max(toldel, 0.25*tol); + tolpt[0] = std::min(av1 + toldel, tol); +#ifdef DEBUG_BLEND + of << "410 1 0 0" << std::endl; + of << "1" << std::endl; + of << tmin << " " << tolpt << " 0 " << tmax << " " << tolpt << " 0 " << std::endl; + of << "410 1 0 0" << std::endl; + of << "1" << std::endl; + of << tmin << " " << av1-tolfac*av2del << " 0 " << tmax << " " << av1-tolfac*av2del << " 0 " << std::endl; +#endif + if (an > 0) + { + intersectCurvePoint(cv2.get(), tolpt, tol2, intpar, intcv); + tolpt[0] = av1 - std::min(toldel, tol-av1); + intersectCurvePoint(cv2.get(), tolpt, tol2, intpar_n, intcv_n); + if (intpar_n.size() > 0) + intpar.insert(intpar.end(), intpar_n.begin(), intpar_n.end()); + } + + if (intpar.size() > 0) + { + std::sort(intpar.begin(), intpar.end()); + splitpar = (start) ? intpar[0] : intpar[intpar.size()-1]; + } +#ifdef DEBUG_BLEND + else + { + //int nmbsplit = 0; + int splitsgn = (start) ? 1 : -1; + vector<Point> der(2); + for (size_t kr=0; kr<intpar1.size(); ++kr) + { + cv1_2->point(der, intpar1[kr], 1); + if (splitsgn*der[1][0] > 0.0) + { + // splitpar += intpar1[kr]; + // nmbsplit++; + splitpar = (start) ? std::max(splitpar, intpar1[kr]) : + std::min(splitpar, intpar1[kr]); + } + } + for (size_t kr=0; kr<intpar2.size(); ++kr) + { + cv2_2->point(der, intpar2[kr], 1); + if (splitsgn*der[1][0] > 0.0) + { + // splitpar += intpar2[kr]; + // nmbsplit++; + splitpar = (start) ? std::max(splitpar, intpar2[kr]) : + std::min(splitpar, intpar2[kr]); + } + } + for (size_t kr=0; kr<intpar3.size(); ++kr) + { + cv3_2->point(der, intpar3[kr], 1); + if (splitsgn*der[1][0] > 0.0) + { + // splitpar += intpar3[kr]; + // nmbsplit++; + splitpar = (start) ? std::max(splitpar, intpar3[kr]) : + std::min(splitpar, intpar3[kr]); + } + } + } +#endif + if (splitpar > tmin && splitpar < tmax) //nmbsplit > 0) + { + //splitpar /= (double)nmbsplit; + if (start) + { + size_t kr; + for (kr=0; kr<perm.size() && param[perm[kr]] <= splitpar; ++kr) + linear.push_back(points[perm[kr]]); + for (; kr<perm.size(); ++kr) + remaining.push_back(points[perm[kr]]); + } + else + { + size_t kr; + for (kr=0; kr<perm.size() && param[perm[kr]] < splitpar; ++kr) + remaining.push_back(points[perm[kr]]); + for (; kr<perm.size(); ++kr) + linear.push_back(points[perm[kr]]); + } + } + else + remaining.insert(remaining.end(), points.begin(), points.end()); + + return true; +} + + +//=========================================================================== +void RevEngUtils::identifyEndPoints(vector<RevEngPoint*> edge_pts, shared_ptr<CurveOnSurface>& sfcv, + RevEngPoint*& first_pt, double& t1, + RevEngPoint*& last_pt, double& t2) +//=========================================================================== +{ + shared_ptr<ParamCurve> pcrv = sfcv->parameterCurve(); + shared_ptr<ParamCurve> spacecrv = sfcv->spaceCurve(); + bool parpref = sfcv->parPref(); + t1 = sfcv->endparam(); + t2 = sfcv->startparam(); + double tpar, dist; + Point close; + double t3 = sfcv->startparam(); + double t4 = sfcv->endparam(); + if (pcrv && parpref) + { + for (size_t ki=0; ki<edge_pts.size(); ++ki) + { + Vector2D uv = edge_pts[ki]->getPar(); + Point ppt(uv[0], uv[1]); + pcrv->closestPoint(ppt, t3, t4, tpar, close, dist); + if (tpar < t1) + { + t1 = tpar; + first_pt = edge_pts[ki]; + } + if (tpar > t2) + { + t2 = tpar; + last_pt = edge_pts[ki]; + } + } + } + else + { + for (size_t ki=0; ki<edge_pts.size(); ++ki) + { + Vector3D xyz = edge_pts[ki]->getPoint(); + Point ppt(xyz[0], xyz[1], xyz[2]); + spacecrv->closestPoint(ppt, t3, t4, tpar, close, dist); + if (tpar < t1) + { + t1 = tpar; + first_pt = edge_pts[ki]; + } + if (tpar > t2) + { + t2 = tpar; + last_pt = edge_pts[ki]; + } + } + } +} + + +//=========================================================================== +void RevEngUtils::setLoopSeq(vector<shared_ptr<CurveOnSurface> >& cvs) +//=========================================================================== +{ + if (cvs.size() <= 1) + return; + + Point pos1 = cvs[0]->ParamCurve::point(cvs[0]->endparam()); + for (size_t ki=1; ki<cvs.size(); ++ki) + { + Point pos2 = cvs[ki]->ParamCurve::point(cvs[ki]->startparam()); + Point pos3 = cvs[ki]->ParamCurve::point(cvs[ki]->endparam()); + double dd2 = pos1.dist(pos2); + double dd3 = pos1.dist(pos3); + for (size_t kj=ki+1; kj<cvs.size(); ++kj) + { + Point pos4 = cvs[kj]->ParamCurve::point(cvs[kj]->startparam()); + Point pos5 = cvs[kj]->ParamCurve::point(cvs[kj]->endparam()); + double dd4 = pos1.dist(pos4); + double dd5 = pos1.dist(pos5); + if (std::min(dd4,dd5) < std::min(dd2,dd3)) + { + std::swap(cvs[ki], cvs[kj]); + std::swap(dd2, dd4); + std::swap(dd3, dd5); + } + } + if (dd3 < dd2) + cvs[ki]->reverseParameterDirection(); + pos1 = cvs[ki]->ParamCurve::point(cvs[ki]->endparam()); + } +} + + +//=========================================================================== +void RevEngUtils::identifyConGroups(vector<RevEngPoint*>& init, + vector<vector<RevEngPoint*> >& groups) +//=========================================================================== +{ + // The points may belong to different regions and have different + // classifications. Mark to identify + int mark = 1; + for (size_t ki=0; ki<init.size(); ++ki) + init[ki]->setMarkIx(mark); + + for (size_t ki=0; ki<init.size(); ++ki) + { + if (init[ki]->visited()) + continue; + vector<RevEngPoint*> curr_group; + init[ki]->fetchConnectedMarked(mark, curr_group); + groups.push_back(curr_group); + } + + for (size_t ki=0; ki<init.size(); ++ki) + { + init[ki]->unsetMarkIx(); + init[ki]->unsetVisited(); + } + + // Sort groups according to size + for (size_t ki=0; ki<groups.size(); ++ki) + for (size_t kj=ki+1; kj<groups.size(); ++kj) + if (groups[kj].size() > groups[ki].size()) + std::swap(groups[ki], groups[kj]); +} + + diff --git a/gotools-core/include/GoTools/geometry/streamable_doxymain.h b/gotools-core/include/GoTools/geometry/streamable_doxymain.h index 79405f69..1795bd0d 100644 --- a/gotools-core/include/GoTools/geometry/streamable_doxymain.h +++ b/gotools-core/include/GoTools/geometry/streamable_doxymain.h @@ -37,8 +37,8 @@ * written agreement between you and SINTEF ICT. */ -#ifndef _PARAMETRIZATION_DOXYMAIN_H -#define _PARAMETRIZATION_DOXYMAIN_H +#ifndef _STREAMABLE_DOXYMAIN_H +#define _STREAMABLE_DOXYMAIN_H /** \page streamable_doc The g2-format, GoTools file format for geometry entities @@ -652,4 +652,4 @@ have degenerate corners (=0) flag for centre degeneracy is false. */ -#endif // _PARAMETRIZATION_DOXYMAIN_H +#endif // _STREAMABLE_DOXYMAIN_H