/* 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 # include #endif /* Definitions internal to the SK implementation */ #include #ifdef _FREESG_INTERNAL # define Strlcpy AG_Strlcpy # define Strlcat AG_Strlcat # 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 *name; size_t size; Uint flags; void (*init)(void *, Uint32); void (*destroy)(void *); int (*load)(struct sk *, void *, AG_DataSource *); int (*save)(struct sk *, void *, AG_DataSource *); void (*draw_relative)(void *, struct sk_view *); void (*draw_absolute)(void *, struct sk_view *); void (*redraw)(void *, struct sk_view *); void (*edit)(void *, struct ag_widget *, struct sk_view *); M_Real (*proximity)(void *, const M_Vector3 *, M_Vector3 *); int (*del)(void *); int (*move)(void *, const M_Vector3 *, const M_Vector3 *); SK_Status (*constrained)(void *); } SK_NodeOps; AG_TAILQ_HEAD(sk_nodeq,sk_node); /* Sketch node instance */ typedef struct sk_node { char name[SK_NODE_NAME_MAX]; Uint32 handle; /* Unique handle for this node class */ const SK_NodeOps *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 *sk; /* Back pointer to sk */ struct sk_node *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 **refNodes; /* References to other nodes */ Uint nRefNodes; struct sk_constraint **cons; /* Constraint edges (optimization) */ Uint nCons; Uint nEdges; /* For solver (optimization) */ 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 *n1; SK_Node *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 *n1; SK_Node *n2; AG_TAILQ_ENTRY(sk_constraint) constraints; } SK_Constraint; /* Rigid cluster of constrained nodes */ typedef struct sk_cluster { Uint32 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 *n[3]; /* Nodes (n0 = unknown) */ SK_Constraint *ct01, *ct02; /* Constraints */ AG_TAILQ_ENTRY(sk_insn) insns; } SK_Insn; /* Intersection computation routine between two nodes */ typedef struct sk_intersect_fn { const char *type1; const char *type2; void (*fn)(struct sk_group *, void *, void *); } SK_IntersectFn; /* Generic geometrical operation on a set of nodes */ typedef struct sk_geometry_fn { const char *name; const char *mask; void (*fn)(struct sk *, int, struct sk_node **); } 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) */ AG_Mutex lock; const struct ag_unit *uLen; /* Length unit */ SK_Node *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 **skElements; extern Uint skElementsCnt; extern const char *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 *SK_New(void *, const char *); void *SK_Edit(void *); void SK_RenderNode(SK *, SK_Node *, struct sk_view *); void SK_RenderAbsolute(SK *, struct sk_view *); void SK_RegisterClass(SK_NodeOps *); int SK_NodeOfClass(void *, const char *); void SK_NodeInit(void *, const void *, Uint32, Uint); void SK_NodeSetName(void *, const char *, ...); SK_Node *SK_NodeNew(void *); int SK_NodeDel(void *); void SK_NodeAttach(void *, void *); void SK_NodeDetach(void *, void *); void SK_NodeMoveUp(void *); void SK_NodeMoveDown(void *); void SK_NodeMoveHead(void *); void SK_NodeMoveTail(void *); void SK_NodeMoveToParent(void *, void *); int SK_NodeLoadGeneric(SK *, SK_Node **, AG_DataSource *); void SK_GetNodeTransform(void *, M_Matrix44 *); void SK_GetNodeTransformInverse(void *, M_Matrix44 *); void SK_NodeAddReference(void *, void *); void SK_NodeDelReference(void *, void *); void SK_NodeAddConstraint(void *, SK_Constraint *); void SK_NodeDelConstraint(void *, SK_Constraint *); Uint32 SK_GenNodeName(SK *, const char *); Uint32 SK_GenClusterName(SK *); M_Color SK_NodeColor(void *, const M_Color *); void SK_NodeRedraw(void *, struct sk_view *); void *SK_ReadRef(AG_DataSource *, SK *, const char *); void SK_WriteRef(AG_DataSource *, void *); void SK_SetLengthUnit(SK *, const struct ag_unit *); void *SK_ProximitySearch(SK *, const char *, const M_Vector3 *, M_Vector3 *, void *); int SK_Solve(SK *); void SK_FreeClusters(SK *); void SK_FreeInsns(SK *); void SK_InitCluster(SK_Cluster *, Uint32); void SK_FreeCluster(SK_Cluster *); void SK_CopyCluster(const SK_Cluster *, SK_Cluster *); int SK_NodeInCluster(const SK_Node *, const SK_Cluster *); SK_Constraint *SK_AddConstraint(SK_Cluster *, void *, void *, enum sk_constraint_type, ...); SK_Constraint *SK_AddConstraintCopy(SK_Cluster *, const SK_Constraint *); SK_Constraint *SK_DupConstraint(const SK_Constraint *); void SK_DelConstraint(SK_Cluster *, SK_Constraint *); int SK_DelSimilarConstraint(SK_Cluster *, const SK_Constraint *); int SK_CompareConstraints(const SK_Constraint *, const SK_Constraint *); Uint SK_ConstraintsToSubgraph(const SK_Cluster *, const SK_Node *, const SK_Cluster *, SK_Constraint *[2]); SK_Insn *SK_AddInsn(SK *, enum sk_insn_type, ...); int SK_ExecInsn(SK *, const SK_Insn *); int SK_ExecProgram(SK *); void SK_SetStatus(SK *, SK_Status, const char *, ...); void SK_ClearProgramState(SK *); M_Vector3 SK_NodeDir(void *); void *SK_FindNode(SK *, Uint32, const char *); void *SK_FindNodeByName(SK *, const char *); SK_Cluster *SK_FindCluster(SK *, Uint32); SK_Constraint *SK_FindConstraint(const SK_Cluster *, enum sk_constraint_type, void *, void *); SK_Constraint *SK_FindSimilarConstraint(const SK_Cluster *, const SK_Constraint *); SK_Constraint *SK_ConstrainedNodes(const SK_Cluster *, const SK_Node *, const SK_Node *); Uint SK_NodeConstraintCount(const SK_Cluster *, void *); void SK_ComputeIntersections(SK_Group *, SK_Node *, SK_Node *); void SK_GeometryMenu(struct sk_view *, void *); #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 *sk) { #if 1 if (SK_Solve(sk) != 0) { fprintf(stderr, "%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 *pair, void *n1, void *n2) { return ((pair->n1 == n1 && pair->n2 == n2) || (pair->n1 == n2 && pair->n2 == n1)); } static __inline__ void SK_SuppressConstraints(void *p) { SKNODE(p)->flags |= SK_NODE_SUPCONSTRAINTS; } static __inline__ void SK_UnsuppressConstraints(void *p) { SKNODE(p)->flags &= ~(SK_NODE_SUPCONSTRAINTS); } /* Return the absolute position of a node. */ static __inline__ M_Vector3 SK_Pos(void *p) { SK_Node *node = p; M_Matrix44 T; M_Vector3 v = M_VecZero3(); SK_GetNodeTransform(node, &T); M_MatMult44Vector3v(&v, &T); return (v); } /* Return the absolute position of a node. */ static __inline__ M_Vector2 SK_Pos2(void *p) { SK_Node *node = p; M_Matrix44 T; M_Vector3 v = M_VecZero3(); SK_GetNodeTransform(node, &T); M_MatMult44Vector3v(&v, &T); return M_Vector3to2(v); } __END_DECLS #include #endif /* _FREESG_SK_SK_H_ */