Blender V5.0
node_geo_mesh_primitive_circle.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include "BKE_material.hh"
6#include "BKE_mesh.hh"
7
8#include "NOD_rna_define.hh"
9
11#include "UI_resources.hh"
12
13#include "BLI_array_utils.hh"
14
16
17#include "node_geometry_util.hh"
18
19#include "RNA_enum_types.hh"
20
22
24
26{
27 b.add_input<decl::Int>("Vertices")
28 .default_value(32)
29 .min(3)
30 .description("Number of vertices on the circle");
31 b.add_input<decl::Float>("Radius")
32 .default_value(1.0f)
33 .min(0.0f)
34 .subtype(PROP_DISTANCE)
35 .description("Distance of the vertices from the origin");
36 b.add_output<decl::Geometry>("Mesh");
37}
38
39static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
40{
41 layout->use_property_split_set(true);
42 layout->use_property_decorate_set(false);
43 layout->prop(ptr, "fill_type", UI_ITEM_NONE, std::nullopt, ICON_NONE);
44}
45
46static void node_init(bNodeTree * /*tree*/, bNode *node)
47{
49
51
52 node->storage = node_storage;
53}
54
55static int circle_vert_total(const GeometryNodeMeshCircleFillType fill_type, const int verts_num)
56{
57 switch (fill_type) {
60 return verts_num;
62 return verts_num + 1;
63 }
65 return 0;
66}
67
68static int circle_edge_total(const GeometryNodeMeshCircleFillType fill_type, const int verts_num)
69{
70 switch (fill_type) {
73 return verts_num;
75 return verts_num * 2;
76 }
78 return 0;
79}
80
81static int circle_corner_total(const GeometryNodeMeshCircleFillType fill_type, const int verts_num)
82{
83 switch (fill_type) {
85 return 0;
87 return verts_num;
89 return verts_num * 3;
90 }
92 return 0;
93}
94
95static int circle_face_total(const GeometryNodeMeshCircleFillType fill_type, const int verts_num)
96{
97 switch (fill_type) {
99 return 0;
101 return 1;
103 return verts_num;
104 }
106 return 0;
107}
108
109static Bounds<float3> calculate_bounds_circle(const float radius, const int verts_num)
110{
111 return geometry::calculate_bounds_radial_primitive(0.0f, radius, verts_num, 0.0f);
112}
113
114static Mesh *create_circle_mesh(const float radius,
115 const int verts_num,
116 const GeometryNodeMeshCircleFillType fill_type)
117{
118 Mesh *mesh = BKE_mesh_new_nomain(circle_vert_total(fill_type, verts_num),
119 circle_edge_total(fill_type, verts_num),
120 circle_face_total(fill_type, verts_num),
121 circle_corner_total(fill_type, verts_num));
123 MutableSpan<float3> positions = mesh->vert_positions_for_write();
124 MutableSpan<int2> edges = mesh->edges_for_write();
125 MutableSpan<int> face_offsets = mesh->face_offsets_for_write();
126 MutableSpan<int> corner_verts = mesh->corner_verts_for_write();
127 MutableSpan<int> corner_edges = mesh->corner_edges_for_write();
128 bke::mesh_smooth_set(*mesh, false);
129
130 /* Assign vertex coordinates. */
131 const float angle_delta = 2.0f * (M_PI / float(verts_num));
132 for (const int i : IndexRange(verts_num)) {
133 const float angle = i * angle_delta;
134 positions[i] = float3(std::cos(angle) * radius, std::sin(angle) * radius, 0.0f);
135 }
137 positions.last() = float3(0);
138 }
139
140 /* Create outer edges. */
141 for (const int i : IndexRange(verts_num)) {
142 int2 &edge = edges[i];
143 edge[0] = i;
144 edge[1] = (i + 1) % verts_num;
145 }
146
147 /* Create triangle fan edges. */
149 for (const int i : IndexRange(verts_num)) {
150 int2 &edge = edges[verts_num + i];
151 edge[0] = verts_num;
152 edge[1] = i;
153 }
154 }
155
156 /* Create corners and faces. */
157 if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_NGON) {
158 face_offsets.first() = 0;
159 face_offsets.last() = corner_verts.size();
160
163
164 mesh->tag_loose_edges_none();
165 }
166 else if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN) {
167 for (const int i : face_offsets.index_range()) {
168 face_offsets[i] = 3 * i;
169 }
170 for (const int i : IndexRange(verts_num)) {
171 corner_verts[3 * i] = i;
172 corner_edges[3 * i] = i;
173
174 corner_verts[3 * i + 1] = (i + 1) % verts_num;
175 corner_edges[3 * i + 1] = verts_num + ((i + 1) % verts_num);
176
177 corner_verts[3 * i + 2] = verts_num;
178 corner_edges[3 * i + 2] = verts_num + i;
179 }
180 }
181
182 mesh->tag_loose_verts_none();
183 mesh->tag_overlapping_none();
184 mesh->bounds_set_eager(calculate_bounds_circle(radius, verts_num));
185
186 return mesh;
187}
188
190{
191 const NodeGeometryMeshCircle &storage = node_storage(params.node());
193
194 const float radius = params.extract_input<float>("Radius");
195 const int verts_num = params.extract_input<int>("Vertices");
196 if (verts_num < 3) {
197 params.error_message_add(NodeWarningType::Info, TIP_("Vertices must be at least 3"));
198 params.set_default_remaining_outputs();
199 return;
200 }
201
202 Mesh *mesh = create_circle_mesh(radius, verts_num, fill);
203
204 params.set_output("Mesh", GeometrySet::from_mesh(mesh));
205}
206
207static void node_rna(StructRNA *srna)
208{
210 "fill_type",
211 "Fill Type",
212 "",
216 nullptr,
217 true);
218}
219
220static void node_register()
221{
222 static blender::bke::bNodeType ntype;
223
224 geo_node_type_base(&ntype, "GeometryNodeMeshCircle", GEO_NODE_MESH_PRIMITIVE_CIRCLE);
225 ntype.ui_name = "Mesh Circle";
226 ntype.ui_description = "Generate a circular ring of edges";
227 ntype.enum_name_legacy = "MESH_PRIMITIVE_CIRCLE";
229 ntype.initfunc = node_init;
231 ntype, "NodeGeometryMeshCircle", node_free_standard_storage, node_copy_standard_storage);
234 ntype.declare = node_declare;
236
237 node_rna(ntype.rna_ext.srna);
238}
240
241} // namespace blender::nodes::node_geo_mesh_primitive_circle_cc
General operations, lookup, etc. for materials.
void BKE_id_material_eval_ensure_default_slot(ID *id)
Mesh * BKE_mesh_new_nomain(int verts_num, int edges_num, int faces_num, int corners_num)
#define NODE_STORAGE_FUNCS(StorageT)
Definition BKE_node.hh:1240
#define NODE_CLASS_GEOMETRY
Definition BKE_node.hh:461
#define GEO_NODE_MESH_PRIMITIVE_CIRCLE
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define M_PI
#define TIP_(msgid)
GeometryNodeMeshCircleFillType
@ GEO_NODE_MESH_CIRCLE_FILL_NGON
@ GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN
@ GEO_NODE_MESH_CIRCLE_FILL_NONE
static double angle(const Eigen::Vector3d &v1, const Eigen::Vector3d &v2)
Definition IK_Math.h:117
#define NOD_REGISTER_NODE(REGISTER_FUNC)
#define NOD_storage_enum_accessors(member)
@ PROP_DISTANCE
Definition RNA_types.hh:256
#define UI_ITEM_NONE
constexpr int64_t size() const
Definition BLI_span.hh:493
constexpr T & first() const
Definition BLI_span.hh:679
constexpr IndexRange index_range() const
Definition BLI_span.hh:670
constexpr T & last(const int64_t n=0) const
Definition BLI_span.hh:689
nullptr float
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void fill_index_range(MutableSpan< T > span, const T start=0)
void node_register_type(bNodeType &ntype)
Definition node.cc:2416
void mesh_smooth_set(Mesh &mesh, bool use_smooth, bool keep_sharp_edges=false)
void node_type_storage(bNodeType &ntype, std::optional< StringRefNull > storagename, void(*freefunc)(bNode *node), void(*copyfunc)(bNodeTree *dest_ntree, bNode *dest_node, const bNode *src_node))
Definition node.cc:5414
Bounds< float3 > calculate_bounds_radial_primitive(float radius_top, float radius_bottom, int segments, float height)
static void node_layout(uiLayout *layout, bContext *, PointerRNA *ptr)
static int circle_edge_total(const GeometryNodeMeshCircleFillType fill_type, const int verts_num)
static int circle_corner_total(const GeometryNodeMeshCircleFillType fill_type, const int verts_num)
static int circle_vert_total(const GeometryNodeMeshCircleFillType fill_type, const int verts_num)
static Mesh * create_circle_mesh(const float radius, const int verts_num, const GeometryNodeMeshCircleFillType fill_type)
static int circle_face_total(const GeometryNodeMeshCircleFillType fill_type, const int verts_num)
static Bounds< float3 > calculate_bounds_circle(const float radius, const int verts_num)
PropertyRNA * RNA_def_node_enum(StructRNA *srna, const char *identifier, const char *ui_name, const char *ui_description, const EnumPropertyItem *static_items, const EnumRNAAccessors accessors, std::optional< int > default_value, const EnumPropertyItemFunc item_func, const bool allow_animation)
VecBase< int32_t, 2 > int2
VecBase< float, 3 > float3
void geo_node_type_base(blender::bke::bNodeType *ntype, std::string idname, const std::optional< int16_t > legacy_type)
void node_free_standard_storage(bNode *node)
Definition node_util.cc:42
void node_copy_standard_storage(bNodeTree *, bNode *dest_node, const bNode *src_node)
Definition node_util.cc:54
const EnumPropertyItem rna_enum_node_geometry_mesh_circle_fill_type_items[]
#define min(a, b)
Definition sort.cc:36
StructRNA * srna
void * storage
Defines a node type.
Definition BKE_node.hh:238
std::string ui_description
Definition BKE_node.hh:244
void(* initfunc)(bNodeTree *ntree, bNode *node)
Definition BKE_node.hh:289
NodeGeometryExecFunction geometry_node_execute
Definition BKE_node.hh:354
const char * enum_name_legacy
Definition BKE_node.hh:247
void(* draw_buttons)(uiLayout *, bContext *C, PointerRNA *ptr)
Definition BKE_node.hh:259
NodeDeclareFunction declare
Definition BKE_node.hh:362
static GeometrySet from_mesh(Mesh *mesh, GeometryOwnershipType ownership=GeometryOwnershipType::Owned)
void use_property_decorate_set(bool is_sep)
void use_property_split_set(bool value)
void prop(PointerRNA *ptr, PropertyRNA *prop, int index, int value, eUI_Item_Flag flag, std::optional< blender::StringRef > name_opt, int icon, std::optional< blender::StringRef > placeholder=std::nullopt)
i
Definition text_draw.cc:230
PointerRNA * ptr
Definition wm_files.cc:4238