//----------------------------------------------------------------------------- // The parametric structure of our sketch, in multiple groups, that generate // geometric entities and surfaces. // // Copyright 2008-2013 Jonathan Westhues. //----------------------------------------------------------------------------- #ifndef __SKETCH_H #define __SKETCH_H class hGroup; class hRequest; class hEntity; class hParam; class hStyle; class hConstraint; class hEquation; class Entity; class Param; class Equation; class Style; // All of the hWhatever handles are a 32-bit ID, that is used to represent // some data structure in the sketch. class hGroup { public: // bits 15: 0 -- group index uint32_t v; inline hEntity entity(int i) const; inline hParam param(int i) const; inline hEquation equation(int i) const; }; class hRequest { public: // bits 15: 0 -- request index uint32_t v; inline hEntity entity(int i) const; inline hParam param(int i) const; inline bool IsFromReferences() const; }; class hEntity { public: // bits 15: 0 -- entity index // 31:16 -- request index uint32_t v; inline bool isFromRequest() const; inline hRequest request() const; inline hGroup group() const; inline hEquation equation(int i) const; }; class hParam { public: // bits 15: 0 -- param index // 31:16 -- request index uint32_t v; inline hRequest request() const; }; class hStyle { public: uint32_t v; }; class EntityId { public: uint32_t v; // entity ID, starting from 0 }; class EntityMap { public: int tag; EntityId h; hEntity input; int copyNumber; // (input, copyNumber) gets mapped to ((Request)xxx).entity(h.v) void Clear() {} }; // A set of requests. Every request must have an associated group. class Group { public: static const hGroup HGROUP_REFERENCES; int tag; hGroup h; enum { DRAWING_3D = 5000, DRAWING_WORKPLANE = 5001, EXTRUDE = 5100, LATHE = 5101, ROTATE = 5200, TRANSLATE = 5201, LINKED = 5300 }; int type; int order; hGroup opA; hGroup opB; bool visible; bool suppress; bool relaxConstraints; bool allowRedundant; bool allDimsReference; double scale; bool clean; hEntity activeWorkplane; double valA; double valB; double valC; RgbaColor color; struct { int how; int dof; List remove; } solved; enum { // For drawings in 2d WORKPLANE_BY_POINT_ORTHO = 6000, WORKPLANE_BY_LINE_SEGMENTS = 6001, // For extrudes, translates, and rotates ONE_SIDED = 7000, TWO_SIDED = 7001 }; int subtype; bool skipFirst; // for step and repeat ops struct { Quaternion q; hEntity origin; hEntity entityB; hEntity entityC; bool swapUV; bool negateU; bool negateV; } predef; SPolygon polyLoops; SBezierLoopSetSet bezierLoops; SBezierList bezierOpens; enum { POLY_GOOD = 0, POLY_NOT_CLOSED = 1, POLY_NOT_COPLANAR = 2, POLY_SELF_INTERSECTING = 3, POLY_ZERO_LEN_EDGE = 4 }; struct { int how; SEdge notClosedAt; Vector errorPointAt; } polyError; bool booleanFailed; SShell thisShell; SShell runningShell; SMesh thisMesh; SMesh runningMesh; bool displayDirty; SMesh displayMesh; SEdgeList displayEdges; SOutlineList displayOutlines; enum { COMBINE_AS_UNION = 0, COMBINE_AS_DIFFERENCE = 1, COMBINE_AS_ASSEMBLE = 2 }; int meshCombine; bool forceToMesh; IdList remap; enum { REMAP_PRIME = 19477 }; int remapCache[REMAP_PRIME]; std::string linkFile; std::string linkFileRel; SMesh impMesh; SShell impShell; EntityList impEntity; std::string name; void Activate(); std::string DescriptionString(); void Clear(); static void AddParam(ParamList *param, hParam hp, double v); void Generate(EntityList *entity, ParamList *param); bool IsSolvedOkay(); void TransformImportedBy(Vector t, Quaternion q); // When a request generates entities from entities, and the source // entities may have come from multiple requests, it's necessary to // remap the entity ID so that it's still unique. We do this with a // mapping list. enum { REMAP_LAST = 1000, REMAP_TOP = 1001, REMAP_BOTTOM = 1002, REMAP_PT_TO_LINE = 1003, REMAP_LINE_TO_FACE = 1004, REMAP_LATHE_START = 1006, REMAP_LATHE_END = 1007, REMAP_PT_TO_ARC = 1008, REMAP_PT_TO_NORMAL = 1009, }; hEntity Remap(hEntity in, int copyNumber); void MakeExtrusionLines(EntityList *el, hEntity in); void MakeLatheCircles(IdList *el, IdList *param, hEntity in, Vector pt, Vector axis, int ai); void MakeExtrusionTopBottomFaces(EntityList *el, hEntity pt); void CopyEntity(EntityList *el, Entity *ep, int timesApplied, int remap, hParam dx, hParam dy, hParam dz, hParam qw, hParam qvx, hParam qvy, hParam qvz, bool asTrans, bool asAxisAngle); void AddEq(IdList *l, Expr *expr, int index); void GenerateEquations(IdList *l); bool IsVisible(); int GetNumConstraints(); Vector ExtrusionGetVector(); void ExtrusionForceVectorTo(const Vector &v); // Assembling the curves into loops, and into a piecewise linear polygon // at the same time. void AssembleLoops(bool *allClosed, bool *allCoplanar, bool *allNonZeroLen); void GenerateLoops(); // And the mesh stuff Group *PreviousGroup(); Group *RunningMeshGroup(); bool IsMeshGroup(); void GenerateShellAndMesh(); template void GenerateForStepAndRepeat(T *steps, T *outs); template void GenerateForBoolean(T *a, T *b, T *o, int how); void GenerateDisplayItems(); void DrawDisplayItems(int t); void Draw(); RgbaColor GetLoopSetFillColor(SBezierLoopSet *sbls, bool *allSame, Vector *errorAt); void FillLoopSetAsPolygon(SBezierLoopSet *sbls); void DrawFilledPaths(); SPolygon GetPolygon(); static void MenuGroup(int id); }; // A user request for some primitive or derived operation; for example a // line, or a step and repeat. class Request { public: // Some predefined requests, that are present in every sketch. static const hRequest HREQUEST_REFERENCE_XY; static const hRequest HREQUEST_REFERENCE_YZ; static const hRequest HREQUEST_REFERENCE_ZX; int tag; hRequest h; // Types of requests enum { WORKPLANE = 100, DATUM_POINT = 101, LINE_SEGMENT = 200, CUBIC = 300, CUBIC_PERIODIC = 301, CIRCLE = 400, ARC_OF_CIRCLE = 500, TTF_TEXT = 600 }; int type; int extraPoints; hEntity workplane; // or Entity::FREE_IN_3D hGroup group; hStyle style; bool construction; std::string str; std::string font; static hParam AddParam(ParamList *param, hParam hp); void Generate(EntityList *entity, ParamList *param) const; std::string DescriptionString() const; int IndexOfPoint(hEntity he) const; void Clear() {} }; #define MAX_POINTS_IN_ENTITY (12) class EntityBase { public: int tag; hEntity h; static const hEntity FREE_IN_3D; static const hEntity NO_ENTITY; enum { POINT_IN_3D = 2000, POINT_IN_2D = 2001, POINT_N_TRANS = 2010, POINT_N_ROT_TRANS = 2011, POINT_N_COPY = 2012, POINT_N_ROT_AA = 2013, NORMAL_IN_3D = 3000, NORMAL_IN_2D = 3001, NORMAL_N_COPY = 3010, NORMAL_N_ROT = 3011, NORMAL_N_ROT_AA = 3012, DISTANCE = 4000, DISTANCE_N_COPY = 4001, FACE_NORMAL_PT = 5000, FACE_XPROD = 5001, FACE_N_ROT_TRANS = 5002, FACE_N_TRANS = 5003, FACE_N_ROT_AA = 5004, WORKPLANE = 10000, LINE_SEGMENT = 11000, CUBIC = 12000, CUBIC_PERIODIC = 12001, CIRCLE = 13000, ARC_OF_CIRCLE = 14000, TTF_TEXT = 15000 }; int type; hGroup group; hEntity workplane; // or Entity::FREE_IN_3D // When it comes time to draw an entity, we look here to get the // defining variables. hEntity point[MAX_POINTS_IN_ENTITY]; int extraPoints; hEntity normal; hEntity distance; // The only types that have their own params are points, normals, // and directions. hParam param[7]; // Transformed points/normals/distances have their numerical base Vector numPoint; Quaternion numNormal; double numDistance; std::string str; std::string font; // For entities that are derived by a transformation, the number of // times to apply the transformation. int timesApplied; Quaternion GetAxisAngleQuaternion(int param0) const; ExprQuaternion GetAxisAngleQuaternionExprs(int param0) const; bool IsCircle() const; Expr *CircleGetRadiusExpr() const; double CircleGetRadiusNum() const; void ArcGetAngles(double *thetaa, double *thetab, double *dtheta) const; bool HasVector() const; ExprVector VectorGetExprs() const; Vector VectorGetNum() const; Vector VectorGetRefPoint() const; Vector VectorGetStartPoint() const; // For distances bool IsDistance() const; double DistanceGetNum() const; Expr *DistanceGetExpr() const; void DistanceForceTo(double v); bool IsWorkplane() const; // The plane is points P such that P dot (xn, yn, zn) - d = 0 void WorkplaneGetPlaneExprs(ExprVector *n, Expr **d) const; ExprVector WorkplaneGetOffsetExprs() const; Vector WorkplaneGetOffset() const; EntityBase *Normal() const; bool IsFace() const; ExprVector FaceGetNormalExprs() const; Vector FaceGetNormalNum() const; ExprVector FaceGetPointExprs() const; Vector FaceGetPointNum() const; bool IsPoint() const; // Applies for any of the point types Vector PointGetNum() const; ExprVector PointGetExprs() const; void PointGetExprsInWorkplane(hEntity wrkpl, Expr **u, Expr **v) const; void PointForceTo(Vector v); // These apply only the POINT_N_ROT_TRANS, which has an assoc rotation Quaternion PointGetQuaternion() const; void PointForceQuaternionTo(Quaternion q); bool IsNormal() const; // Applies for any of the normal types Quaternion NormalGetNum() const; ExprQuaternion NormalGetExprs() const; void NormalForceTo(Quaternion q); Vector NormalU() const; Vector NormalV() const; Vector NormalN() const; ExprVector NormalExprsU() const; ExprVector NormalExprsV() const; ExprVector NormalExprsN() const; Vector CubicGetStartNum() const; Vector CubicGetFinishNum() const; ExprVector CubicGetStartTangentExprs() const; ExprVector CubicGetFinishTangentExprs() const; Vector CubicGetStartTangentNum() const; Vector CubicGetFinishTangentNum() const; bool HasEndpoints() const; Vector EndpointStart() const; Vector EndpointFinish() const; void AddEq(IdList *l, Expr *expr, int index) const; void GenerateEquations(IdList *l) const; void Clear() {} }; class Entity : public EntityBase { public: // Necessary for Entity e = {} to zero-initialize, since // classes with base classes are not aggregates and // the default constructor does not initialize members. // // Note EntityBase({}); without explicitly value-initializing // the base class, MSVC2013 will default-initialize it, leaving // POD members with indeterminate value. Entity() : EntityBase({}), forceHidden(), actPoint(), actNormal(), actDistance(), actVisible(), style(), construction(), beziers(), edges(), edgesChordTol(), screenBBox(), screenBBoxValid(), dogd() {}; // A linked entity that was hidden in the source file ends up hidden // here too. bool forceHidden; // All points/normals/distances have their numerical value; this is // a convenience, to simplify the link/assembly code, so that the // part is entirely described by the entities. Vector actPoint; Quaternion actNormal; double actDistance; // and the shown state also gets saved here, for later import bool actVisible; hStyle style; bool construction; SBezierList beziers; SEdgeList edges; double edgesChordTol; BBox screenBBox; bool screenBBoxValid; // Routines to draw and hit-test the representation of the entity // on-screen. struct { bool drawing; Point2d mp; double dmin; Vector refp; double lineWidth; double stippleScale; int stippleType; int data; } dogd; // state for drawing or getting distance (for hit testing) void LineDrawOrGetDistance(Vector a, Vector b, bool maybeFat=false, int userData = -1); void DrawOrGetDistance(); bool IsStylable() const; bool IsVisible() const; bool PointIsFromReferences() const; void ComputeInterpolatingSpline(SBezierList *sbl, bool periodic) const; void GenerateBezierCurves(SBezierList *sbl) const; void GenerateEdges(SEdgeList *el, bool includingConstruction=false); static void DrawAll(bool drawAsHidden); void Draw(bool drawAsHidden); double GetDistance(Point2d mp); Vector GetReferencePos(); void CalculateNumerical(bool forExport); std::string DescriptionString() const; SBezierList *GetOrGenerateBezierCurves(); SEdgeList *GetOrGenerateEdges(); BBox GetOrGenerateScreenBBox(bool *hasBBox); void Clear() { beziers.l.Clear(); edges.l.Clear(); } }; class EntReqTable { public: typedef struct { int reqType; int entType; int points; bool useExtraPoints; bool hasNormal; bool hasDistance; const char *description; } TableEntry; static const TableEntry Table[]; static const char *DescriptionForRequest(int req); static void CopyEntityInfo(const TableEntry *te, int extraPoints, int *ent, int *req, int *pts, bool *hasNormal, bool *hasDistance); static bool GetRequestInfo(int req, int extraPoints, int *ent, int *pts, bool *hasNormal, bool *hasDistance); static bool GetEntityInfo(int ent, int extraPoints, int *req, int *pts, bool *hasNormal, bool *hasDistance); static int GetRequestForEntity(int ent); }; class Param { public: int tag; hParam h; double val; bool known; bool free; // Used only in the solver hParam substd; static const hParam NO_PARAM; void Clear() {} }; class hConstraint { public: uint32_t v; inline hEquation equation(int i) const; }; class ConstraintBase { public: int tag; hConstraint h; static const hConstraint NO_CONSTRAINT; enum { POINTS_COINCIDENT = 20, PT_PT_DISTANCE = 30, PT_PLANE_DISTANCE = 31, PT_LINE_DISTANCE = 32, PT_FACE_DISTANCE = 33, PROJ_PT_DISTANCE = 34, PT_IN_PLANE = 41, PT_ON_LINE = 42, PT_ON_FACE = 43, EQUAL_LENGTH_LINES = 50, LENGTH_RATIO = 51, EQ_LEN_PT_LINE_D = 52, EQ_PT_LN_DISTANCES = 53, EQUAL_ANGLE = 54, EQUAL_LINE_ARC_LEN = 55, LENGTH_DIFFERENCE = 56, SYMMETRIC = 60, SYMMETRIC_HORIZ = 61, SYMMETRIC_VERT = 62, SYMMETRIC_LINE = 63, AT_MIDPOINT = 70, HORIZONTAL = 80, VERTICAL = 81, DIAMETER = 90, PT_ON_CIRCLE = 100, SAME_ORIENTATION = 110, ANGLE = 120, PARALLEL = 121, PERPENDICULAR = 122, ARC_LINE_TANGENT = 123, CUBIC_LINE_TANGENT = 124, CURVE_CURVE_TANGENT = 125, EQUAL_RADIUS = 130, WHERE_DRAGGED = 200, COMMENT = 1000 }; int type; hGroup group; hEntity workplane; // These are the parameters for the constraint. double valA; hEntity ptA; hEntity ptB; hEntity entityA; hEntity entityB; hEntity entityC; hEntity entityD; bool other; bool other2; bool reference; // a ref dimension, that generates no eqs std::string comment; // since comments are represented as constraints bool HasLabel() const; void Generate(IdList *l) const; void GenerateReal(IdList *l) const; // Some helpers when generating symbolic constraint equations void ModifyToSatisfy(); void AddEq(IdList *l, Expr *expr, int index) const; static Expr *DirectionCosine(hEntity wrkpl, ExprVector ae, ExprVector be); static Expr *Distance(hEntity workplane, hEntity pa, hEntity pb); static Expr *PointLineDistance(hEntity workplane, hEntity pt, hEntity ln); static Expr *PointPlaneDistance(ExprVector p, hEntity plane); static Expr *VectorsParallel(int eq, ExprVector a, ExprVector b); static ExprVector PointInThreeSpace(hEntity workplane, Expr *u, Expr *v); void Clear() {} }; class Constraint : public ConstraintBase { public: // See Entity::Entity(). Constraint() : ConstraintBase({}), disp(), dogd() {} // These define how the constraint is drawn on-screen. struct { Vector offset; hStyle style; } disp; // State for drawing or getting distance (for hit testing). struct { bool drawing; Point2d mp; double dmin; Vector refp; SEdgeList *sel; } dogd; double GetDistance(Point2d mp); Vector GetLabelPos(); Vector GetReferencePos(); void Draw(); void GetEdges(SEdgeList *sel); bool IsStylable() const; hStyle GetStyle() const; bool HasLabel() const; void LineDrawOrGetDistance(Vector a, Vector b); bool IsVisible() const; void DrawOrGetDistance(Vector *labelPos); std::string Label() const; bool DoLineExtend(Vector p0, Vector p1, Vector pt, double salient); void DoArcForAngle(Vector a0, Vector da, Vector b0, Vector db, Vector offset, Vector *ref, bool trim); void DoArrow(Vector p, Vector dir, Vector n, double width, double angle, double da); void DoLineWithArrows(Vector ref, Vector a, Vector b, bool onlyOneExt); int DoLineTrimmedAgainstBox(Vector ref, Vector a, Vector b, bool extend, Vector gr, Vector gu, double swidth, double sheight); int DoLineTrimmedAgainstBox(Vector ref, Vector a, Vector b, bool extend = true); void DoLabel(Vector ref, Vector *labelPos, Vector gr, Vector gu); void StippledLine(Vector a, Vector b); void DoProjectedPoint(Vector *p); void DoEqualLenTicks(Vector a, Vector b, Vector gn); void DoEqualRadiusTicks(hEntity he); std::string DescriptionString() const; static hConstraint AddConstraint(Constraint *c, bool rememberForUndo); static hConstraint AddConstraint(Constraint *c); static void MenuConstrain(int id); static void DeleteAllConstraintsFor(int type, hEntity entityA, hEntity ptA); static hConstraint ConstrainCoincident(hEntity ptA, hEntity ptB); static hConstraint Constrain(int type, hEntity ptA, hEntity ptB, hEntity entityA); static hConstraint Constrain(int type, hEntity ptA, hEntity ptB, hEntity entityA, hEntity entityB, bool other, bool other2); }; class hEquation { public: uint32_t v; inline bool isFromConstraint() const; inline hConstraint constraint() const; }; class Equation { public: int tag; hEquation h; Expr *e; void Clear() {} }; class Style { public: int tag; hStyle h; enum { STIPPLE_CONTINUOUS = 0, STIPPLE_DASH = 1, STIPPLE_LONG_DASH = 2, STIPPLE_DASH_DOT = 3, STIPPLE_DASH_DOT_DOT = 4, STIPPLE_DOT = 5, STIPPLE_FREEHAND = 6, STIPPLE_ZIGZAG = 7, LAST_STIPPLE = STIPPLE_ZIGZAG }; enum { // If an entity has no style, then it will be colored according to // whether the group that it's in is active or not, whether it's // construction or not, and so on. NO_STYLE = 0, ACTIVE_GRP = 1, CONSTRUCTION = 2, INACTIVE_GRP = 3, DATUM = 4, SOLID_EDGE = 5, CONSTRAINT = 6, SELECTED = 7, HOVERED = 8, CONTOUR_FILL = 9, NORMALS = 10, ANALYZE = 11, DRAW_ERROR = 12, DIM_SOLID = 13, HIDDEN_EDGE = 14, OUTLINE = 15, FIRST_CUSTOM = 0x100 }; std::string name; enum { UNITS_AS_PIXELS = 0, UNITS_AS_MM = 1 }; double width; int widthAs; double textHeight; int textHeightAs; enum { ORIGIN_LEFT = 0x01, ORIGIN_RIGHT = 0x02, ORIGIN_BOT = 0x04, ORIGIN_TOP = 0x08 }; int textOrigin; double textAngle; RgbaColor color; bool filled; RgbaColor fillColor; bool visible; bool exportable; int stippleType; double stippleScale; int zIndex; // The default styles, for entities that don't have a style assigned yet, // and for datums and such. typedef struct { hStyle h; const char *cnfPrefix; RgbaColor color; double width; int zIndex; } Default; static const Default Defaults[]; static std::string CnfColor(const std::string &prefix); static std::string CnfWidth(const std::string &prefix); static std::string CnfTextHeight(const std::string &prefix); static std::string CnfPrefixToName(const std::string &prefix); static void CreateAllDefaultStyles(); static void CreateDefaultStyle(hStyle h); static void FillDefaultStyle(Style *s, const Default *d = NULL); static void FreezeDefaultStyles(); static void LoadFactoryDefaults(); static void AssignSelectionToStyle(uint32_t v); static uint32_t CreateCustomStyle(bool rememberForUndo = true); static RgbaColor RewriteColor(RgbaColor rgb); static Style *Get(hStyle hs); static RgbaColor Color(hStyle hs, bool forExport=false); static RgbaColor FillColor(hStyle hs, bool forExport=false); static float Width(hStyle hs); static RgbaColor Color(int hs, bool forExport=false); static float Width(int hs); static double WidthMm(int hs); static double TextHeight(hStyle hs); static double DefaultTextHeight(); static bool Exportable(int hs); static hStyle ForEntity(hEntity he); static int PatternType(hStyle hs); static double StippleScaleMm(hStyle hs); std::string DescriptionString() const; void Clear() {} }; inline hEntity hGroup::entity(int i) const { hEntity r; r.v = 0x80000000 | (v << 16) | (uint32_t)i; return r; } inline hParam hGroup::param(int i) const { hParam r; r.v = 0x80000000 | (v << 16) | (uint32_t)i; return r; } inline hEquation hGroup::equation(int i) const { hEquation r; r.v = (v << 16) | 0x80000000 | (uint32_t)i; return r; } inline bool hRequest::IsFromReferences() const { if(v == Request::HREQUEST_REFERENCE_XY.v) return true; if(v == Request::HREQUEST_REFERENCE_YZ.v) return true; if(v == Request::HREQUEST_REFERENCE_ZX.v) return true; return false; } inline hEntity hRequest::entity(int i) const { hEntity r; r.v = (v << 16) | (uint32_t)i; return r; } inline hParam hRequest::param(int i) const { hParam r; r.v = (v << 16) | (uint32_t)i; return r; } inline bool hEntity::isFromRequest() const { if(v & 0x80000000) return false; else return true; } inline hRequest hEntity::request() const { hRequest r; r.v = (v >> 16); return r; } inline hGroup hEntity::group() const { hGroup r; r.v = (v >> 16) & 0x3fff; return r; } inline hEquation hEntity::equation(int i) const { hEquation r; r.v = v | 0x40000000; return r; } inline hRequest hParam::request() const { hRequest r; r.v = (v >> 16); return r; } inline hEquation hConstraint::equation(int i) const { hEquation r; r.v = (v << 16) | (uint32_t)i; return r; } inline bool hEquation::isFromConstraint() const { if(v & 0xc0000000) return false; else return true; } inline hConstraint hEquation::constraint() const { hConstraint r; r.v = (v >> 16); return r; } // The format for entities stored on the clipboard. class ClipboardRequest { public: int type; int extraPoints; hStyle style; std::string str; std::string font; bool construction; Vector point[MAX_POINTS_IN_ENTITY]; double distance; hEntity oldEnt; hEntity oldPointEnt[MAX_POINTS_IN_ENTITY]; hRequest newReq; }; #endif