/* Public domain */ #ifndef _FREESG_SK_SK_H_ #define _FREESG_SK_SK_H_ #include /* For AG_Surface */ #include /* Macros around precision-specific GL calls */ #if defined(_FREESG_INTERNAL) || defined(_USE_SK_GL) # include #endif /* Definitions internal to the SK implementation */ #include #if defined(_FREESG_INTERNAL) || defined(_USE_SK_GL) # include #endif #ifdef _FREESG_INTERNAL # define NODE SGNODE # define NODE_OPS SGNODE_OPS # undef MAX # define MAX(h,i) ((h) > (i) ? (h) : (i)) # undef MIN # define MIN(l,o) ((l) < (o) ? (l) : (o)) #endif /* _FREESG_INTERNAL */ #define SK_TYPE_NAME_MAX 64 #define SK_NODE_NAME_MAX (SK_TYPE_NAME_MAX+12) #define SK_NAME_MAX (0xffffffff-1) #define SK_STATUS_MAX 2048 #define SK_GROUP_NAME_MAX 64 struct sk; struct sk_node; struct sk_point; struct sk_constraint; struct sk_group; struct sk_view; struct ag_widget; struct ag_unit; /* Solver status */ typedef enum sk_status { SK_INVALID, /* No solutions */ SK_WELL_CONSTRAINED, /* Finite number of solution */ SK_UNDER_CONSTRAINED, /* Infinite number of solutions */ SK_OVER_CONSTRAINED /* Redundant constraints */ } SK_Status; /* Operations for sketch node classes. */ typedef struct sk_node_ops { const char *_Nonnull name; size_t size; Uint flags; void (*_Nonnull init)(void *_Nonnull, Uint); void (*_Nullable destroy)(void *_Nonnull); int (*_Nullable load)(struct sk *_Nonnull, void *_Nonnull, AG_DataSource *_Nonnull); int (*_Nullable save)(struct sk *_Nonnull, void *_Nonnull, AG_DataSource *_Nonnull); void (*_Nullable draw)(void *_Nonnull, struct sk_view *_Nonnull); void (*_Nullable redraw)(void *_Nonnull, struct sk_view *_Nonnull); void (*_Nullable edit)(void *_Nonnull, struct ag_widget *_Nonnull, struct sk_view *_Nonnull); M_Real (*_Nonnull proximity)(void *_Nonnull, const M_Vector3 *_Nonnull, M_Vector3 *_Nonnull); int (*_Nullable del)(void *_Nonnull); int (*_Nullable move)(void *_Nonnull, const M_Vector3 *_Nonnull, const M_Vector3 *_Nonnull); SK_Status (*_Nullable constrained)(void *_Nonnull); } SK_NodeOps; AG_TAILQ_HEAD(sk_nodeq,sk_node); /* Sketch node instance */ typedef struct sk_node { char name[SK_NODE_NAME_MAX]; Uint handle; /* Unique handle for this node class */ const SK_NodeOps *_Nonnull ops; Uint flags; #define SK_NODE_SELECTED 0x01 /* For editor */ #define SK_NODE_MOUSEOVER 0x02 /* For editor */ #define SK_NODE_MOVED 0x04 /* For editor */ #define SK_NODE_SUPCONSTRAINTS 0x08 /* Suppress constraints */ #define SK_NODE_FIXED 0x10 /* Treat position as known */ #define SK_NODE_KNOWN 0x20 /* Position found by solver */ #define SK_NODE_CHECKED 0x40 /* For constrainedness check */ struct sk *_Nullable sk; /* Back pointer to sk */ struct sk_node *_Nullable pNode; /* Back pointer to parent node */ M_Matrix44 T; /* Transformation from parent */ struct sk_nodeq cnodes; /* Siblings */ Uint nRefs; /* Reference count (optimization) */ struct sk_node *_Nonnull *_Nonnull refNodes; /* Referenced nodes */ Uint nRefNodes; struct sk_constraint *_Nonnull *_Nonnull cons; /* Constraint edges */ Uint nCons; /* (optimization) */ Uint nEdges; /* For solver */ AG_TAILQ_ENTRY(sk_node) sknodes; /* Entry in transformation tree */ AG_TAILQ_ENTRY(sk_node) nodes; /* Entry in flat node list */ AG_TAILQ_ENTRY(sk_node) rnodes; /* Reverse entry (optimization) */ } SK_Node; /* Pair of nodes */ typedef struct sk_node_pair { SK_Node *_Nonnull n1; SK_Node *_Nonnull n2; } SK_NodePair; /* Type of constraint between nodes */ enum sk_constraint_type { SK_DISTANCE, SK_INCIDENT, /* Translated to DISTANCE(0) */ SK_ANGLE, SK_PERPENDICULAR, /* Translated to ANGLE(90deg) */ SK_PARALLEL, /* Translated to ANGLE(0deg) */ SK_TANGENT, SK_CONSTRAINT_LAST #define SK_CONSTRAINT_ANY SK_CONSTRAINT_LAST }; /* Constraint between two nodes */ typedef struct sk_constraint { enum sk_constraint_type uType; /* Constraint type (user-provided) */ enum sk_constraint_type type; /* Constraint type (translated) */ union { M_Real dist; /* DISTANCE value */ M_Real angle; /* ANGLE value (radians) */ } data; #ifdef _FREESG_INTERNAL #define ct_distance data.dist #define ct_angle data.angle #endif SK_Node *_Nonnull n1; SK_Node *_Nonnull n2; AG_TAILQ_ENTRY(sk_constraint) constraints; } SK_Constraint; /* Rigid cluster of constrained nodes */ typedef struct sk_cluster { Uint name; AG_TAILQ_HEAD_(sk_constraint) edges; AG_TAILQ_ENTRY(sk_cluster) clusters; } SK_Cluster; /* Placement instruction generated by graph analysis */ typedef struct sk_insn { enum sk_insn_type { SK_COMPOSE_PAIR, /* Find n2 from n1 */ SK_COMPOSE_RING /* Find n3 from n1 and n2, assuming (n1,n2,n3) is a constrained ring */ } type; SK_Node *_Nullable n[3]; /* Nodes (n0 = unknown) */ SK_Constraint *_Nonnull ct01; /* Constraint #1 */ SK_Constraint *_Nonnull ct02; /* Constraint #2 */ AG_TAILQ_ENTRY(sk_insn) insns; } SK_Insn; /* Intersection computation routine between two nodes */ typedef struct sk_intersect_fn { const char *_Nonnull type1; /* Class of node #1 */ const char *_Nonnull type2; /* Class of node #2 */ void (*_Nonnull fn)(struct sk_group *_Nonnull, void *_Nonnull, void *_Nonnull); } SK_IntersectFn; /* Generic geometrical operation on a set of nodes */ typedef struct sk_geometry_fn { const char *_Nonnull name; const char *_Nonnull mask; void (*_Nonnull fn)(struct sk *_Nonnull, int, struct sk_node *_Nonnull *_Nonnull); } SK_GeometryFn; /* Sketch class */ typedef struct sk { struct ag_object obj; Uint flags; #define SK_SKIP_UNKNOWN_NODES 0x01 /* Ignore unimplemented nodes in load (otherwise fail) */ _Nonnull AG_Mutex lock; const struct ag_unit *_Nonnull uLen; /* Length unit */ SK_Node *_Nullable root; /* Root node */ struct sk_nodeq nodes; /* Flat node list */ SK_Status status; /* Constrainedness status */ char statusText[SK_STATUS_MAX]; /* Status text */ Uint nSolutions; /* Total number of solutions (if well-constrained) */ /* For internal use by constraint solver */ SK_Cluster ctGraph; /* Original constraint graph */ AG_TAILQ_HEAD_(sk_cluster) clusters; /* Rigid clusters */ AG_TAILQ_HEAD_(sk_insn) insns; /* Construction steps */ AG_TAILQ_HEAD_(sk_group) group; /* Item groups */ } SK; #define SKNODE(node) ((SK_Node *)(node)) #define SKNODE_SELECTED(node) (((SK_Node *)(node))->flags & SK_NODE_SELECTED) #define SK_MOVED(node) (((SK_Node *)(node))->flags & SK_NODE_MOVED) #define SK_FIXED(node) (((SK_Node *)(node))->flags & SK_NODE_FIXED) #define SK_FOREACH_NODE(node, sk, ntype) \ for((node) = (struct ntype *)AG_TAILQ_FIRST(&(sk)->nodes); \ (node) != (struct ntype *)AG_TAILQ_END(&(sk)->nodes); \ (node) = (struct ntype *)AG_TAILQ_NEXT(SKNODE(node),nodes)) #define SK_FOREACH_NODE_CLASS(node, sk, ntype, cn) \ SK_FOREACH_NODE(node,sk,ntype) \ if (!SK_NodeOfClass(SKNODE(node),(cn))) { \ continue; \ } else #define SK_FOREACH_SUBNODE(node, pnode, ntype) \ for((node) = (struct ntype *)AG_TAILQ_FIRST(&(pnode)->nodes); \ (node) != (struct ntype *)AG_TAILQ_END(&(pnode)->cnodes); \ (node) = (struct ntype *)AG_TAILQ_NEXT(SKNODE(node),sknodes)) #define SK_FOREACH_SUBNODE_CLASS(node, pnode, ntype, cn) \ SK_FOREACH_SUBNODE(node,pnode,ntype) \ if (!SK_NodeOfClass(SKNODE(node),(cn))) { \ continue; \ } else /* Standard node classes */ #include #include #include #include #include #include #include #include #include #include __BEGIN_DECLS extern AG_ObjectClass skClass; extern SK_NodeOps *_Nullable *_Nonnull skElements; extern Uint skElementsCnt; extern const char *_Nonnull skConstraintNames[]; extern const SK_IntersectFn skIntersectFns[]; extern const Uint skIntersectFnCount; extern const SK_GeometryFn skGeometryFns[]; extern const Uint skGeometryFnCount; extern SK_NodeOps skNodeOps; void SK_InitSubsystem(void); void SK_DestroySubsystem(void); SK *_Nullable SK_New(void *_Nullable, const char *_Nullable); void *_Nonnull SK_Edit(void *_Nonnull); void SK_RegisterClass(SK_NodeOps *_Nonnull); int SK_NodeOfClass(void *_Nonnull, const char *_Nonnull); SK_Node *_Nonnull SK_NodeNew(void *_Nonnull); void SK_NodeInit(void *_Nonnull, const void *_Nonnull, Uint, Uint); void SK_NodeSetName(void *_Nonnull, const char *_Nonnull, ...); int SK_NodeDel(void *_Nonnull); void SK_NodeAttach(void *_Nonnull, void *_Nonnull); void SK_NodeDetach(void *_Nonnull, void *_Nonnull); void SK_NodeMoveUp(void *_Nonnull); void SK_NodeMoveDown(void *_Nonnull); void SK_NodeMoveHead(void *_Nonnull); void SK_NodeMoveTail(void *_Nonnull); void SK_NodeMoveToParent(void *_Nonnull, void *_Nonnull); void SK_GetNodeTransform(void *_Nonnull, M_Matrix44 *_Nonnull); void SK_GetNodeTransformInverse(void *_Nonnull, M_Matrix44 *_Nonnull); void SK_NodeAddReference(void *_Nonnull, void *_Nonnull); void SK_NodeDelReference(void *_Nonnull, void *_Nonnull); void SK_NodeAddConstraint(void *_Nonnull, SK_Constraint *_Nonnull); void SK_NodeDelConstraint(void *_Nonnull, SK_Constraint *_Nonnull); Uint SK_GenNodeName(SK *_Nonnull, const char *_Nonnull); Uint SK_GenClusterName(SK *_Nonnull); void SK_NodeRedraw(void *_Nonnull, struct sk_view *_Nonnull); M_Color SK_NodeColor(void *_Nonnull, const M_Color *_Nonnull); void *_Nonnull SK_ReadRef(AG_DataSource *_Nonnull, SK *_Nonnull, const char *_Nullable); void SK_WriteRef(AG_DataSource *_Nonnull, void *_Nonnull); void SK_SetLengthUnit(SK *_Nonnull, const struct ag_unit *_Nonnull); void *_Nullable SK_ProximitySearch(SK *_Nonnull, const char *_Nullable, const M_Vector3 *_Nonnull, M_Vector3 *_Nonnull, void *_Nullable); int SK_Solve(SK *_Nonnull); void SK_FreeClusters(SK *_Nonnull); void SK_FreeInsns(SK *_Nonnull); void SK_InitCluster(SK_Cluster *_Nonnull, Uint); void SK_FreeCluster(SK_Cluster *_Nonnull); void SK_CopyCluster(const SK_Cluster *_Nonnull, SK_Cluster *_Nonnull); int SK_NodeInCluster(const SK_Node *_Nonnull, const SK_Cluster *_Nonnull); SK_Constraint *_Nullable SK_AddConstraint(SK_Cluster *_Nonnull, void *_Nonnull, void *_Nonnull, enum sk_constraint_type, ...); SK_Constraint *_Nullable SK_AddConstraintCopy(SK_Cluster *_Nonnull, const SK_Constraint *_Nonnull); SK_Constraint *_Nonnull SK_DupConstraint(const SK_Constraint *_Nonnull); void SK_DelConstraint(SK_Cluster *_Nonnull, SK_Constraint *_Nonnull); int SK_DelSimilarConstraint(SK_Cluster *_Nonnull, const SK_Constraint *_Nonnull); int SK_CompareConstraints(const SK_Constraint *_Nonnull, const SK_Constraint *_Nonnull); Uint SK_ConstraintsToSubgraph(const SK_Cluster *_Nonnull, const SK_Node *_Nonnull, const SK_Cluster *_Nonnull, SK_Constraint *_Nonnull [_Nonnull 2]); SK_Insn *_Nonnull SK_AddInsn(SK *_Nonnull, enum sk_insn_type, ...); int SK_ExecInsn(SK *_Nonnull, const SK_Insn *_Nonnull); int SK_ExecProgram(SK *_Nonnull); void SK_SetStatus(SK *_Nonnull, SK_Status, const char *_Nonnull, ...); void SK_ClearProgramState(SK *_Nonnull); M_Vector3 SK_NodeDir(void *_Nonnull); void *_Nullable SK_FindNode(SK *_Nonnull, Uint, const char *_Nonnull); void *_Nullable SK_FindNodeByName(SK *_Nonnull, const char *_Nonnull); M_Vector3 SK_Pos(void *_Nonnull); M_Vector2 SK_Pos2(void *_Nonnull); SK_Cluster *_Nullable SK_FindCluster(SK *_Nonnull, Uint); SK_Constraint *_Nullable SK_FindConstraint(const SK_Cluster *_Nonnull, enum sk_constraint_type, void *_Nonnull, void *_Nonnull); SK_Constraint *_Nullable SK_FindSimilarConstraint(const SK_Cluster *_Nonnull, const SK_Constraint *_Nonnull); SK_Constraint *_Nullable SK_ConstrainedNodes(const SK_Cluster *_Nonnull, const SK_Node *_Nonnull, const SK_Node *_Nonnull); Uint SK_NodeConstraintCount(const SK_Cluster *_Nonnull, void *_Nonnull); void SK_ComputeIntersections(SK_Group *_Nonnull, SK_Node *_Nonnull, SK_Node *_Nonnull); void SK_GeometryMenu(struct sk_view *_Nonnull, void *_Nonnull); #define SK_Identity(n) M_MatIdentity44v(&SKNODE(n)->T) #define SK_Translate(n,x,y) M_MatTranslate44(&SKNODE(n)->T,(v).x,(v).y,0.0) #define SK_Translatev(n,v) M_MatTranslate44(&SKNODE(n)->T,(v)->x,(v)->y,0.0) #define SK_TranslateVec(n,v) M_MatTranslate44(&SKNODE(n)->T,(v).x,(v).y,0.0) #define SK_Translate2(n,x,y) M_MatTranslate44(&SKNODE(n)->T,(x),(y),0.0) #define SK_Rotatev(n,theta) M_MatRotate44K(&SKNODE(n)->T,(theta)) #define SK_MatrixCopy(nDst,nSrc) M_MatCopy44(&SKNODE(nDst)->T,&SKNODE(nSrc)->T) #define SK_LockNode(n) AG_ObjectLock(SKNODE(n)->sk) #define SK_UnlockNode(n) AG_ObjectUnlock(SKNODE(n)->sk) /* Update the sketch. */ static __inline__ void SK_Update(SK *_Nonnull sk) { #if 1 if (SK_Solve(sk) != 0) AG_Verbose("%s: Sketch is not solvable\n", AGOBJECT(sk)->name); #else if (SK_Solve(sk) == 0) SK_ExecProgram(sk); #endif } static __inline__ int SK_CompareNodePair(SK_NodePair *_Nonnull pair, void *_Nonnull n1, void *_Nonnull n2) { return ((pair->n1 == n1 && pair->n2 == n2) || (pair->n1 == n2 && pair->n2 == n1)); } static __inline__ void SK_SuppressConstraints(void *_Nonnull p) { SKNODE(p)->flags |= SK_NODE_SUPCONSTRAINTS; } static __inline__ void SK_UnsuppressConstraints(void *_Nonnull p) { SKNODE(p)->flags &= ~(SK_NODE_SUPCONSTRAINTS); } __END_DECLS #include #endif /* _FREESG_SK_SK_H_ */