58 } |
58 } |
59 |
59 |
60 return 0.0; |
60 return 0.0; |
61 } |
61 } |
62 |
62 |
|
63 static Matrix shearMatrixForPlane(Canvas* renderer) |
|
64 { |
|
65 const Plane& plane = renderer->drawPlane(); |
|
66 Axis localx, localy; |
|
67 renderer->getRelativeAxes(localx, localy); |
|
68 Axis localz = renderer->getRelativeZ(); |
|
69 Matrix shearMatrix = Matrix::identity; |
|
70 Vertex normalAsVertex = Vertex::fromVector(plane.normal); |
|
71 |
|
72 // Compute shear matrix values. The (Y, X) cell means a slope for Y in regard to X. |
|
73 // If x grows by 2, y grows by 2 times this value. In the circle primitives, |
|
74 // depth is Y, but in the orthogonal view, depth is Z. So Y and Z must be swapped. |
|
75 if (not qFuzzyCompare(normalAsVertex[localz], 0.0)) |
|
76 { |
|
77 // The slope of the vector is 90° offset from the normal vector. So Y/X slope is |
|
78 // -X/Y from the normal vector. |
|
79 shearMatrix(Y, X) = -normalAsVertex[localx] / normalAsVertex[localz]; |
|
80 shearMatrix(Y, Z) = -normalAsVertex[localy] / normalAsVertex[localz]; |
|
81 } |
|
82 |
|
83 return shearMatrix; |
|
84 } |
63 |
85 |
64 void CircleMode::endDraw() |
86 void CircleMode::endDraw() |
65 { |
87 { |
66 Model model {m_documents}; |
88 Model model {m_documents}; |
67 PrimitiveModel primitiveModel; |
89 PrimitiveModel primitiveModel; |
70 primitiveModel.ringNumber = 0; |
92 primitiveModel.ringNumber = 0; |
71 double dist0 (getCircleDrawDist (0)); |
93 double dist0 (getCircleDrawDist (0)); |
72 double dist1 (getCircleDrawDist (1)); |
94 double dist1 (getCircleDrawDist (1)); |
73 LDDocument* primitiveFile; |
95 LDDocument* primitiveFile; |
74 Matrix transform; |
96 Matrix transform; |
|
97 |
75 bool circleOrDisc = false; |
98 bool circleOrDisc = false; |
76 |
99 |
77 if (dist1 < dist0) |
100 if (dist1 < dist0) |
78 qSwap(dist0, dist1); |
101 qSwap(dist0, dist1); |
79 |
102 |
80 if (dist0 == dist1) |
103 if (qFuzzyCompare(dist0, dist1)) |
81 { |
104 { |
82 // If the radii are the same, there's no ring space to fill. Use a circle. |
105 // Special case: radii are the same, there's no area. Use a circle. |
83 primitiveModel.type = PrimitiveModel::Circle; |
106 primitiveModel.type = PrimitiveModel::Circle; |
84 primitiveFile = primitives()->getPrimitive(primitiveModel); |
107 primitiveFile = primitives()->getPrimitive(primitiveModel); |
85 transform = Matrix::fromRotationMatrix(renderer()->currentCamera().transformationMatrix(dist0)); |
108 // transform = shearMatrixForPlane(renderer()); |
|
109 transform = Matrix::fromQMatrix(renderer()->currentCamera().transformationMatrix(1)); |
|
110 transform *= Matrix::scaleMatrix(dist0); |
86 circleOrDisc = true; |
111 circleOrDisc = true; |
87 } |
112 } |
88 else if (dist0 == 0 or dist1 == 0) |
113 else if (qFuzzyCompare(dist0, 0) or qFuzzyCompare(dist1, 0)) |
89 { |
114 { |
90 // If either radii is 0, use a disc. |
115 // Special case #2: one radius is 0, so use a disc. |
91 primitiveModel.type = PrimitiveModel::Disc; |
116 primitiveModel.type = PrimitiveModel::Disc; |
92 primitiveFile = primitives()->getPrimitive(primitiveModel); |
117 primitiveFile = primitives()->getPrimitive(primitiveModel); |
93 transform = Matrix::fromRotationMatrix(renderer()->currentCamera().transformationMatrix((dist0 != 0) ? dist0 : dist1)); |
118 //transform = shearMatrixForPlane(renderer()); |
|
119 transform = Matrix::fromQMatrix(renderer()->currentCamera().transformationMatrix(1)); |
|
120 transform *= Matrix::scaleMatrix(max(dist0, dist1)); |
94 circleOrDisc = true; |
121 circleOrDisc = true; |
95 } |
122 } |
96 else if (g_RingFinder.findRings(dist0, dist1)) |
123 else if (g_RingFinder.findRings(dist0, dist1)) // Consult the ring finder now |
97 { |
124 { |
98 // The ring finder found a solution, use that. Add the component rings to the file. |
125 // The ring finder found a solution, use that. Add the component rings to the file. |
99 primitiveModel.type = PrimitiveModel::Ring; |
126 primitiveModel.type = PrimitiveModel::Ring; |
100 |
127 |
101 for (const RingFinder::Component& component : g_RingFinder.bestSolution()->getComponents()) |
128 for (const RingFinder::Component& component : g_RingFinder.bestSolution()->getComponents()) |
102 { |
129 { |
103 primitiveModel.ringNumber = component.num; |
130 primitiveModel.ringNumber = component.num; |
104 primitiveFile = primitives()->getPrimitive(primitiveModel); |
131 primitiveFile = primitives()->getPrimitive(primitiveModel); |
105 Matrix matrix = Matrix::fromRotationMatrix(renderer()->currentCamera().transformationMatrix(component.scale)); |
132 Matrix matrix = Matrix::fromQMatrix(renderer()->currentCamera().transformationMatrix(component.scale)); |
|
133 // matrix = shearMatrixForPlane(renderer()) * matrix; |
106 model.emplace<LDSubfileReference>(primitiveFile->name(), matrix, m_drawedVerts.first()); |
134 model.emplace<LDSubfileReference>(primitiveFile->name(), matrix, m_drawedVerts.first()); |
107 } |
135 } |
108 } |
136 } |
109 else |
137 else |
110 { |
138 { |
116 double y0 = m_drawedVerts[0][localy]; |
144 double y0 = m_drawedVerts[0][localy]; |
117 |
145 |
118 Vertex templ; |
146 Vertex templ; |
119 templ.setCoordinate(localx, x0); |
147 templ.setCoordinate(localx, x0); |
120 templ.setCoordinate(localy, y0); |
148 templ.setCoordinate(localy, y0); |
121 templ.setCoordinate(localz, renderer()->getDepthValue()); |
|
122 |
149 |
123 // Calculate circle coords |
150 // Calculate circle coords |
124 QVector<QLineF> c0 = makeCircle(primitiveModel.segments, primitiveModel.divisions, dist0); |
151 QVector<QLineF> c0 = makeCircle(primitiveModel.segments, primitiveModel.divisions, dist0); |
125 QVector<QLineF> c1 = makeCircle(primitiveModel.segments, primitiveModel.divisions, dist1); |
152 QVector<QLineF> c1 = makeCircle(primitiveModel.segments, primitiveModel.divisions, dist1); |
126 |
153 |
139 |
166 |
140 // Ensure the quads always are BFC-front towards the camera |
167 // Ensure the quads always are BFC-front towards the camera |
141 if (static_cast<int>(renderer()->camera()) % 3 <= 0) |
168 if (static_cast<int>(renderer()->camera()) % 3 <= 0) |
142 qSwap(v1, v3); |
169 qSwap(v1, v3); |
143 |
170 |
|
171 // Project the vertices onto the draw plane. |
|
172 for (Vertex* vertex : {&v0, &v1, &v2, &v3}) |
|
173 *vertex = projectToDrawPlane(*vertex); |
|
174 |
144 LDQuadrilateral* quad = model.emplace<LDQuadrilateral>(v0, v1, v2, v3); |
175 LDQuadrilateral* quad = model.emplace<LDQuadrilateral>(v0, v1, v2, v3); |
145 quad->setColor(MainColor); |
176 quad->setColor(MainColor); |
146 } |
177 } |
147 } |
178 } |
148 |
179 |
149 if (circleOrDisc and primitiveFile) |
180 if (circleOrDisc and primitiveFile) |
|
181 { |
150 model.emplace<LDSubfileReference>(primitiveFile->name(), transform, m_drawedVerts.first()); |
182 model.emplace<LDSubfileReference>(primitiveFile->name(), transform, m_drawedVerts.first()); |
|
183 } |
151 |
184 |
152 finishDraw (model); |
185 finishDraw (model); |
153 } |
186 } |
154 |
187 |
155 /* |
188 /* |