Solvespace
247 строк · 8.8 Кб
1//-----------------------------------------------------------------------------
2// Implementation of our Request class; a request is a user-created thing
3// that will generate an entity (line, curve) when the sketch is generated,
4// in the same way that other entities are generated automatically, like
5// by an extrude or a step and repeat.
6//
7// Copyright 2008-2013 Jonathan Westhues.
8//-----------------------------------------------------------------------------
9#include "solvespace.h"
10
11const hRequest Request::HREQUEST_REFERENCE_XY = { 1 };
12const hRequest Request::HREQUEST_REFERENCE_YZ = { 2 };
13const hRequest Request::HREQUEST_REFERENCE_ZX = { 3 };
14
15struct EntReqMapping {
16Request::Type reqType;
17Entity::Type entType;
18int points;
19bool useExtraPoints;
20bool hasNormal;
21bool hasDistance;
22};
23static const EntReqMapping EntReqMap[] = {
24// request type entity type pts xtra? norml dist
25{ Request::Type::WORKPLANE, Entity::Type::WORKPLANE, 1, false, true, false },
26{ Request::Type::DATUM_POINT, (Entity::Type)0, 1, false, false, false },
27{ Request::Type::LINE_SEGMENT, Entity::Type::LINE_SEGMENT, 2, false, false, false },
28{ Request::Type::CUBIC, Entity::Type::CUBIC, 4, true, false, false },
29{ Request::Type::CUBIC_PERIODIC, Entity::Type::CUBIC_PERIODIC, 3, true, false, false },
30{ Request::Type::CIRCLE, Entity::Type::CIRCLE, 1, false, true, true },
31{ Request::Type::ARC_OF_CIRCLE, Entity::Type::ARC_OF_CIRCLE, 3, false, true, false },
32{ Request::Type::TTF_TEXT, Entity::Type::TTF_TEXT, 4, false, true, false },
33{ Request::Type::IMAGE, Entity::Type::IMAGE, 4, false, true, false },
34};
35
36static void CopyEntityInfo(const EntReqMapping *te, int extraPoints,
37Entity::Type *ent, Request::Type *req,
38int *pts, bool *hasNormal, bool *hasDistance)
39{
40int points = te->points;
41if(te->useExtraPoints) points += extraPoints;
42
43if(ent) *ent = te->entType;
44if(req) *req = te->reqType;
45if(pts) *pts = points;
46if(hasNormal) *hasNormal = te->hasNormal;
47if(hasDistance) *hasDistance = te->hasDistance;
48}
49
50bool EntReqTable::GetRequestInfo(Request::Type req, int extraPoints,
51Entity::Type *ent, int *pts, bool *hasNormal, bool *hasDistance)
52{
53for(const EntReqMapping &te : EntReqMap) {
54if(req == te.reqType) {
55CopyEntityInfo(&te, extraPoints, ent, NULL, pts, hasNormal, hasDistance);
56return true;
57}
58}
59return false;
60}
61
62bool EntReqTable::GetEntityInfo(Entity::Type ent, int extraPoints,
63Request::Type *req, int *pts, bool *hasNormal, bool *hasDistance)
64{
65for(const EntReqMapping &te : EntReqMap) {
66if(ent == te.entType) {
67CopyEntityInfo(&te, extraPoints, NULL, req, pts, hasNormal, hasDistance);
68return true;
69}
70}
71return false;
72}
73
74Request::Type EntReqTable::GetRequestForEntity(Entity::Type ent) {
75Request::Type req;
76ssassert(GetEntityInfo(ent, 0, &req, NULL, NULL, NULL),
77"No entity for request");
78return req;
79}
80
81void Request::Generate(IdList<Entity,hEntity> *entity,
82IdList<Param,hParam> *param)
83{
84int points = 0;
85Entity::Type et = (Entity::Type)0;
86bool hasNormal = false;
87bool hasDistance = false;
88int i;
89
90// Request-specific generation.
91switch(type) {
92case Type::TTF_TEXT: {
93// `extraPoints` is storing kerning boolean
94double actualAspectRatio = SS.fonts.AspectRatio(font, str, extraPoints);
95if(EXACT(actualAspectRatio != 0.0)) {
96// We could load the font, so use the actual value.
97aspectRatio = actualAspectRatio;
98}
99if(EXACT(aspectRatio == 0.0)) {
100// We couldn't load the font and we don't have anything saved,
101// so just use 1:1, which is valid for the missing font symbol anyhow.
102aspectRatio = 1.0;
103}
104break;
105}
106
107case Type::IMAGE: {
108auto image = SS.images.find(file);
109if(image != SS.images.end()) {
110std::shared_ptr<Pixmap> pixmap = (*image).second;
111if(pixmap != NULL) {
112aspectRatio = (double)pixmap->width / (double)pixmap->height;
113}
114}
115if(EXACT(aspectRatio == 0.0)) {
116aspectRatio = 1.0;
117}
118break;
119}
120
121default: // most requests don't do anything else
122break;
123}
124
125Entity e = {};
126EntReqTable::GetRequestInfo(type, extraPoints, &et, &points, &hasNormal, &hasDistance);
127
128// Generate the entity that's specific to this request.
129e.type = et;
130e.extraPoints = extraPoints;
131e.group = group;
132e.style = style;
133e.workplane = workplane;
134e.construction = construction;
135e.str = str;
136e.font = font;
137e.file = file;
138e.aspectRatio = aspectRatio;
139e.h = h.entity(0);
140
141// And generate entities for the points
142for(i = 0; i < points; i++) {
143Entity p = {};
144p.workplane = workplane;
145// points start from entity 1, except for datum point case
146p.h = h.entity(i+((et != (Entity::Type)0) ? 1 : 0));
147p.group = group;
148p.style = style;
149p.construction = e.construction;
150if(workplane == Entity::FREE_IN_3D) {
151p.type = Entity::Type::POINT_IN_3D;
152// params for x y z
153p.param[0] = AddParam(param, h.param(16 + 3*i + 0));
154p.param[1] = AddParam(param, h.param(16 + 3*i + 1));
155p.param[2] = AddParam(param, h.param(16 + 3*i + 2));
156} else {
157p.type = Entity::Type::POINT_IN_2D;
158// params for u v
159p.param[0] = AddParam(param, h.param(16 + 3*i + 0));
160p.param[1] = AddParam(param, h.param(16 + 3*i + 1));
161}
162entity->Add(&p);
163e.point[i] = p.h;
164}
165if(hasNormal) {
166Entity n = {};
167n.workplane = workplane;
168n.h = h.entity(32);
169n.group = group;
170n.style = style;
171n.construction = e.construction;
172if(workplane == Entity::FREE_IN_3D) {
173n.type = Entity::Type::NORMAL_IN_3D;
174n.param[0] = AddParam(param, h.param(32+0));
175n.param[1] = AddParam(param, h.param(32+1));
176n.param[2] = AddParam(param, h.param(32+2));
177n.param[3] = AddParam(param, h.param(32+3));
178} else {
179n.type = Entity::Type::NORMAL_IN_2D;
180// and this is just a copy of the workplane quaternion,
181// so no params required
182}
183ssassert(points >= 1, "Positioning a normal requires a point");
184// The point determines where the normal gets displayed on-screen;
185// it's entirely cosmetic.
186n.point[0] = e.point[0];
187entity->Add(&n);
188e.normal = n.h;
189}
190if(hasDistance) {
191Entity d = {};
192d.workplane = workplane;
193d.h = h.entity(64);
194d.group = group;
195d.style = style;
196d.type = Entity::Type::DISTANCE;
197d.param[0] = AddParam(param, h.param(64));
198entity->Add(&d);
199e.distance = d.h;
200}
201
202if(et != (Entity::Type)0) entity->Add(&e);
203}
204
205std::string Request::DescriptionString() const {
206const char *s = "";
207if(h == Request::HREQUEST_REFERENCE_XY) {
208s = "#XY";
209} else if(h == Request::HREQUEST_REFERENCE_YZ) {
210s = "#YZ";
211} else if(h == Request::HREQUEST_REFERENCE_ZX) {
212s = "#ZX";
213} else {
214switch(type) {
215case Type::WORKPLANE: s = "workplane"; break;
216case Type::DATUM_POINT: s = "datum-point"; break;
217case Type::LINE_SEGMENT: s = "line-segment"; break;
218case Type::CUBIC: s = "cubic-bezier"; break;
219case Type::CUBIC_PERIODIC: s = "periodic-cubic"; break;
220case Type::CIRCLE: s = "circle"; break;
221case Type::ARC_OF_CIRCLE: s = "arc-of-circle"; break;
222case Type::TTF_TEXT: s = "ttf-text"; break;
223case Type::IMAGE: s = "image"; break;
224}
225}
226ssassert(s != NULL, "Unexpected request type");
227return ssprintf("r%03x-%s", h.v, s);
228}
229
230int Request::IndexOfPoint(hEntity he) const {
231if(type == Type::DATUM_POINT) {
232return (he == h.entity(0)) ? 0 : -1;
233}
234for(int i = 0; i < MAX_POINTS_IN_ENTITY; i++) {
235if(he == h.entity(i + 1)) {
236return i;
237}
238}
239return -1;
240}
241
242hParam Request::AddParam(IdList<Param,hParam> *param, hParam hp) {
243Param pa = {};
244pa.h = hp;
245param->Add(&pa);
246return hp;
247}
248
249