1 package net.sf.openrocket.util;
3 import net.sf.openrocket.material.Material;
4 import net.sf.openrocket.material.Material.Type;
5 import net.sf.openrocket.motor.Motor;
6 import net.sf.openrocket.rocketcomponent.BodyTube;
7 import net.sf.openrocket.rocketcomponent.Bulkhead;
8 import net.sf.openrocket.rocketcomponent.CenteringRing;
9 import net.sf.openrocket.rocketcomponent.ExternalComponent;
10 import net.sf.openrocket.rocketcomponent.ExternalComponent.Finish;
11 import net.sf.openrocket.rocketcomponent.FinSet.CrossSection;
12 import net.sf.openrocket.rocketcomponent.FreeformFinSet;
13 import net.sf.openrocket.rocketcomponent.IllegalFinPointException;
14 import net.sf.openrocket.rocketcomponent.InnerTube;
15 import net.sf.openrocket.rocketcomponent.InternalComponent;
16 import net.sf.openrocket.rocketcomponent.LaunchLug;
17 import net.sf.openrocket.rocketcomponent.MassComponent;
18 import net.sf.openrocket.rocketcomponent.MotorMount.IgnitionEvent;
19 import net.sf.openrocket.rocketcomponent.NoseCone;
20 import net.sf.openrocket.rocketcomponent.ReferenceType;
21 import net.sf.openrocket.rocketcomponent.Rocket;
22 import net.sf.openrocket.rocketcomponent.RocketComponent;
23 import net.sf.openrocket.rocketcomponent.RocketComponent.Position;
24 import net.sf.openrocket.rocketcomponent.Stage;
25 import net.sf.openrocket.rocketcomponent.Transition;
26 import net.sf.openrocket.rocketcomponent.Transition.Shape;
27 import net.sf.openrocket.rocketcomponent.TrapezoidFinSet;
28 import net.sf.openrocket.rocketcomponent.TubeCoupler;
29 import net.sf.openrocket.startup.Application;
31 import java.awt.Color;
32 import java.util.Random;
34 public class TestRockets {
36 private final String key;
37 private final Random rnd;
40 public TestRockets(String key) {
43 Random rnd = new Random();
44 StringBuilder sb = new StringBuilder();
45 for (int i = 0; i < 6; i++) {
46 int n = rnd.nextInt(62);
48 sb.append((char) ('0' + n));
50 sb.append((char) ('A' + n - 10));
52 sb.append((char) ('a' + n - 36));
59 this.rnd = new Random(key.hashCode());
65 * Create a new test rocket based on the value 'key'. The rocket utilizes most of the
66 * properties and features available. The same key always returns the same rocket,
67 * but different key values produce slightly different rockets. A key value of
68 * <code>null</code> generates a rocket using a random key.
70 * The rocket created by this method is not fly-worthy. It is also NOT guaranteed
71 * that later versions would produce exactly the same rocket!
73 * @return a rocket design.
75 public Rocket makeTestRocket() {
77 Rocket rocket = new Rocket();
79 rocket.setCustomReferenceLength(rnd(0.05));
80 rocket.setDesigner("Designer " + key);
81 rocket.setReferenceType((ReferenceType) randomEnum(ReferenceType.class));
82 rocket.setRevision("Rocket revision " + key);
86 Stage stage = new Stage();
88 rocket.addChild(stage);
91 NoseCone nose = new NoseCone();
93 nose.setAftRadius(rnd(0.03));
94 nose.setAftRadiusAutomatic(rnd.nextBoolean());
95 nose.setAftShoulderCapped(rnd.nextBoolean());
96 nose.setAftShoulderLength(rnd(0.02));
97 nose.setAftShoulderRadius(rnd(0.02));
98 nose.setAftShoulderThickness(rnd(0.002));
99 nose.setClipped(rnd.nextBoolean());
100 nose.setThickness(rnd(0.002));
101 nose.setFilled(rnd.nextBoolean());
102 nose.setForeRadius(rnd(0.1)); // Unset
103 nose.setLength(rnd(0.15));
104 nose.setShapeParameter(rnd(0.5));
105 nose.setType((Shape) randomEnum(Shape.class));
106 stage.addChild(nose);
109 Transition shoulder = new Transition();
111 shoulder.setAftRadius(rnd(0.06));
112 shoulder.setAftRadiusAutomatic(rnd.nextBoolean());
113 shoulder.setAftShoulderCapped(rnd.nextBoolean());
114 shoulder.setAftShoulderLength(rnd(0.02));
115 shoulder.setAftShoulderRadius(rnd(0.05));
116 shoulder.setAftShoulderThickness(rnd(0.002));
117 shoulder.setClipped(rnd.nextBoolean());
118 shoulder.setThickness(rnd(0.002));
119 shoulder.setFilled(rnd.nextBoolean());
120 shoulder.setForeRadius(rnd(0.03));
121 shoulder.setForeRadiusAutomatic(rnd.nextBoolean());
122 shoulder.setForeShoulderCapped(rnd.nextBoolean());
123 shoulder.setForeShoulderLength(rnd(0.02));
124 shoulder.setForeShoulderRadius(rnd(0.02));
125 shoulder.setForeShoulderThickness(rnd(0.002));
126 shoulder.setLength(rnd(0.15));
127 shoulder.setShapeParameter(rnd(0.5));
128 shoulder.setThickness(rnd(0.003));
129 shoulder.setType((Shape) randomEnum(Shape.class));
130 stage.addChild(shoulder);
133 BodyTube body = new BodyTube();
135 body.setThickness(rnd(0.002));
136 body.setFilled(rnd.nextBoolean());
137 body.setIgnitionDelay(rnd.nextDouble() * 3);
138 body.setIgnitionEvent((IgnitionEvent) randomEnum(IgnitionEvent.class));
139 body.setLength(rnd(0.3));
140 body.setMotorMount(rnd.nextBoolean());
141 body.setMotorOverhang(rnd.nextGaussian() * 0.03);
142 body.setOuterRadius(rnd(0.06));
143 body.setRadiusAutomatic(rnd.nextBoolean());
144 stage.addChild(body);
147 Transition boattail = new Transition();
149 boattail.setAftRadius(rnd(0.03));
150 boattail.setAftRadiusAutomatic(rnd.nextBoolean());
151 boattail.setAftShoulderCapped(rnd.nextBoolean());
152 boattail.setAftShoulderLength(rnd(0.02));
153 boattail.setAftShoulderRadius(rnd(0.02));
154 boattail.setAftShoulderThickness(rnd(0.002));
155 boattail.setClipped(rnd.nextBoolean());
156 boattail.setThickness(rnd(0.002));
157 boattail.setFilled(rnd.nextBoolean());
158 boattail.setForeRadius(rnd(0.06));
159 boattail.setForeRadiusAutomatic(rnd.nextBoolean());
160 boattail.setForeShoulderCapped(rnd.nextBoolean());
161 boattail.setForeShoulderLength(rnd(0.02));
162 boattail.setForeShoulderRadius(rnd(0.05));
163 boattail.setForeShoulderThickness(rnd(0.002));
164 boattail.setLength(rnd(0.15));
165 boattail.setShapeParameter(rnd(0.5));
166 boattail.setThickness(rnd(0.003));
167 boattail.setType((Shape) randomEnum(Shape.class));
168 stage.addChild(boattail);
171 MassComponent mass = new MassComponent();
173 mass.setComponentMass(rnd(0.05));
174 mass.setLength(rnd(0.05));
175 mass.setRadialDirection(rnd(100));
176 mass.setRadialPosition(rnd(0.02));
177 mass.setRadius(rnd(0.05));
187 private void setBasics(RocketComponent c) {
188 c.setComment(c.getComponentName() + " comment " + key);
189 c.setName(c.getComponentName() + " name " + key);
191 c.setCGOverridden(rnd.nextBoolean());
192 c.setMassOverridden(rnd.nextBoolean());
193 c.setOverrideCGX(rnd(0.2));
194 c.setOverrideMass(rnd(0.05));
195 c.setOverrideSubcomponents(rnd.nextBoolean());
198 // Only massive components are drawn
199 c.setColor(randomColor());
200 c.setLineStyle((LineStyle) randomEnum(LineStyle.class));
203 if (c instanceof ExternalComponent) {
204 ExternalComponent e = (ExternalComponent) c;
205 e.setFinish((Finish) randomEnum(Finish.class));
207 e.setMaterial(Material.newMaterial(Type.BULK, "Testmat " + d, d, rnd.nextBoolean()));
210 if (c instanceof InternalComponent) {
211 InternalComponent i = (InternalComponent) c;
212 i.setRelativePosition((Position) randomEnum(Position.class));
213 i.setPositionValue(rnd(0.3));
219 private double rnd(double scale) {
220 return (rnd.nextDouble() * 0.2 + 0.9) * scale;
223 private Color randomColor() {
224 return new Color(rnd.nextInt(256), rnd.nextInt(256), rnd.nextInt(256));
227 private <T extends Enum<T>> Enum<T> randomEnum(Class<T> c) {
228 Enum<T>[] values = c.getEnumConstants();
229 if (values.length == 0)
232 return values[rnd.nextInt(values.length)];
239 public Rocket makeSmallFlyable() {
240 double noseconeLength = 0.10, noseconeRadius = 0.01;
241 double bodytubeLength = 0.20, bodytubeRadius = 0.01, bodytubeThickness = 0.001;
244 double finRootChord = 0.04, finTipChord = 0.05, finSweep = 0.01, finThickness = 0.003, finHeight = 0.03;
251 TrapezoidFinSet finset;
253 rocket = new Rocket();
255 stage.setName("Stage1");
257 nosecone = new NoseCone(Transition.Shape.ELLIPSOID, noseconeLength, noseconeRadius);
258 bodytube = new BodyTube(bodytubeLength, bodytubeRadius, bodytubeThickness);
260 finset = new TrapezoidFinSet(finCount, finRootChord, finTipChord, finSweep, finHeight);
263 // Stage construction
264 rocket.addChild(stage);
267 // Component construction
268 stage.addChild(nosecone);
269 stage.addChild(bodytube);
271 bodytube.addChild(finset);
273 Material material = Prefs.getDefaultComponentMaterial(null, Material.Type.BULK);
274 nosecone.setMaterial(material);
275 bodytube.setMaterial(material);
276 finset.setMaterial(material);
278 String id = rocket.newMotorConfigurationID();
279 bodytube.setMotorMount(true);
281 Motor m = Application.getMotorSetDatabase().findMotors(null, null, "B4", Double.NaN, Double.NaN).get(0);
282 bodytube.setMotor(id, m);
283 bodytube.setMotorOverhang(0.005);
284 rocket.getDefaultConfiguration().setMotorConfigurationID(id);
286 rocket.getDefaultConfiguration().setAllStages();
293 public static Rocket makeBigBlue() {
298 FreeformFinSet finset;
301 rocket = new Rocket();
303 stage.setName("Stage1");
305 nosecone = new NoseCone(Transition.Shape.ELLIPSOID, 0.105, 0.033);
306 nosecone.setThickness(0.001);
307 bodytube = new BodyTube(0.69, 0.033, 0.001);
309 finset = new FreeformFinSet();
311 finset.setPoints(new Coordinate[] {
312 new Coordinate(0, 0),
313 new Coordinate(0.115, 0.072),
314 new Coordinate(0.255, 0.072),
315 new Coordinate(0.255, 0.037),
316 new Coordinate(0.150, 0)
318 } catch (IllegalFinPointException e) {
321 finset.setThickness(0.003);
322 finset.setFinCount(4);
324 finset.setCantAngle(0 * Math.PI / 180);
325 System.err.println("Fin cant angle: " + (finset.getCantAngle() * 180 / Math.PI));
327 mcomp = new MassComponent(0.2, 0.03, 0.045 + 0.060);
328 mcomp.setRelativePosition(Position.TOP);
329 mcomp.setPositionValue(0);
331 // Stage construction
332 rocket.addChild(stage);
333 rocket.setPerfectFinish(false);
336 // Component construction
337 stage.addChild(nosecone);
338 stage.addChild(bodytube);
340 bodytube.addChild(finset);
342 bodytube.addChild(mcomp);
344 // Material material = new Material("Test material", 500);
345 // nosecone.setMaterial(material);
346 // bodytube.setMaterial(material);
347 // finset.setMaterial(material);
349 String id = rocket.newMotorConfigurationID();
350 bodytube.setMotorMount(true);
352 // Motor m = Application.getMotorSetDatabase().findMotors(null, null, "F12J", Double.NaN, Double.NaN).get(0);
353 // bodytube.setMotor(id, m);
354 // bodytube.setMotorOverhang(0.005);
355 rocket.getDefaultConfiguration().setMotorConfigurationID(id);
357 rocket.getDefaultConfiguration().setAllStages();
365 public static Rocket makeIsoHaisu() {
369 BodyTube tube1, tube2, tube3;
370 TrapezoidFinSet finset;
371 TrapezoidFinSet auxfinset;
374 final double R = 0.07;
376 rocket = new Rocket();
378 stage.setName("Stage1");
380 nosecone = new NoseCone(Transition.Shape.OGIVE, 0.53, R);
381 nosecone.setThickness(0.005);
382 nosecone.setMassOverridden(true);
383 nosecone.setOverrideMass(0.588);
384 stage.addChild(nosecone);
386 tube1 = new BodyTube(0.505, R, 0.005);
387 tube1.setMassOverridden(true);
388 tube1.setOverrideMass(0.366);
389 stage.addChild(tube1);
391 tube2 = new BodyTube(0.605, R, 0.005);
392 tube2.setMassOverridden(true);
393 tube2.setOverrideMass(0.427);
394 stage.addChild(tube2);
396 tube3 = new BodyTube(1.065, R, 0.005);
397 tube3.setMassOverridden(true);
398 tube3.setOverrideMass(0.730);
399 stage.addChild(tube3);
402 LaunchLug lug = new LaunchLug();
405 TubeCoupler coupler = new TubeCoupler();
406 coupler.setOuterRadiusAutomatic(true);
407 coupler.setThickness(0.005);
408 coupler.setLength(0.28);
409 coupler.setMassOverridden(true);
410 coupler.setOverrideMass(0.360);
411 coupler.setRelativePosition(Position.BOTTOM);
412 coupler.setPositionValue(-0.14);
413 tube1.addChild(coupler);
417 MassComponent mass = new MassComponent(0.05, 0.05, 0.280);
418 mass.setRelativePosition(Position.TOP);
419 mass.setPositionValue(0.2);
420 tube1.addChild(mass);
423 mass = new MassComponent(0.05, 0.05, 0.125);
424 mass.setRelativePosition(Position.TOP);
425 mass.setPositionValue(0.2);
426 tube1.addChild(mass);
429 mass = new MassComponent(0.40, R, 1.500);
430 mass.setRelativePosition(Position.TOP);
431 mass.setPositionValue(0.25);
432 tube1.addChild(mass);
435 auxfinset = new TrapezoidFinSet();
436 auxfinset.setName("CONTROL");
437 auxfinset.setFinCount(2);
438 auxfinset.setRootChord(0.05);
439 auxfinset.setTipChord(0.05);
440 auxfinset.setHeight(0.10);
441 auxfinset.setSweep(0);
442 auxfinset.setThickness(0.008);
443 auxfinset.setCrossSection(CrossSection.AIRFOIL);
444 auxfinset.setRelativePosition(Position.TOP);
445 auxfinset.setPositionValue(0.28);
446 auxfinset.setBaseRotation(Math.PI / 2);
447 tube1.addChild(auxfinset);
452 coupler = new TubeCoupler();
453 coupler.setOuterRadiusAutomatic(true);
454 coupler.setLength(0.28);
455 coupler.setRelativePosition(Position.TOP);
456 coupler.setPositionValue(0.47);
457 coupler.setMassOverridden(true);
458 coupler.setOverrideMass(0.360);
459 tube2.addChild(coupler);
464 mass = new MassComponent(0.1, 0.05, 0.028);
465 mass.setRelativePosition(Position.TOP);
466 mass.setPositionValue(0.14);
467 tube2.addChild(mass);
469 Bulkhead bulk = new Bulkhead();
470 bulk.setOuterRadiusAutomatic(true);
471 bulk.setMassOverridden(true);
472 bulk.setOverrideMass(0.050);
473 bulk.setRelativePosition(Position.TOP);
474 bulk.setPositionValue(0.27);
475 tube2.addChild(bulk);
478 mass = new MassComponent(0.1, 0.05, 0.125);
479 mass.setRelativePosition(Position.TOP);
480 mass.setPositionValue(0.19);
481 tube2.addChild(mass);
485 InnerTube inner = new InnerTube();
486 inner.setOuterRadius(0.08 / 2);
487 inner.setInnerRadius(0.0762 / 2);
488 inner.setLength(0.86);
489 inner.setMassOverridden(true);
490 inner.setOverrideMass(0.388);
491 tube3.addChild(inner);
494 CenteringRing center = new CenteringRing();
495 center.setInnerRadiusAutomatic(true);
496 center.setOuterRadiusAutomatic(true);
497 center.setLength(0.005);
498 center.setMassOverridden(true);
499 center.setOverrideMass(0.038);
500 center.setRelativePosition(Position.BOTTOM);
501 center.setPositionValue(0);
502 tube3.addChild(center);
505 center = new CenteringRing();
506 center.setInnerRadiusAutomatic(true);
507 center.setOuterRadiusAutomatic(true);
508 center.setLength(0.005);
509 center.setMassOverridden(true);
510 center.setOverrideMass(0.038);
511 center.setRelativePosition(Position.TOP);
512 center.setPositionValue(0.28);
513 tube3.addChild(center);
516 center = new CenteringRing();
517 center.setInnerRadiusAutomatic(true);
518 center.setOuterRadiusAutomatic(true);
519 center.setLength(0.005);
520 center.setMassOverridden(true);
521 center.setOverrideMass(0.038);
522 center.setRelativePosition(Position.TOP);
523 center.setPositionValue(0.83);
524 tube3.addChild(center);
530 finset = new TrapezoidFinSet();
531 finset.setRootChord(0.495);
532 finset.setTipChord(0.1);
533 finset.setHeight(0.185);
534 finset.setThickness(0.005);
535 finset.setSweep(0.3);
536 finset.setRelativePosition(Position.BOTTOM);
537 finset.setPositionValue(-0.03);
538 finset.setBaseRotation(Math.PI / 2);
539 tube3.addChild(finset);
542 finset.setCantAngle(0 * Math.PI / 180);
543 System.err.println("Fin cant angle: " + (finset.getCantAngle() * 180 / Math.PI));
546 // Stage construction
547 rocket.addChild(stage);
548 rocket.setPerfectFinish(false);
552 String id = rocket.newMotorConfigurationID();
553 tube3.setMotorMount(true);
555 // Motor m = Application.getMotorSetDatabase().findMotors(null, null, "L540", Double.NaN, Double.NaN).get(0);
556 // tube3.setMotor(id, m);
557 // tube3.setMotorOverhang(0.02);
558 rocket.getDefaultConfiguration().setMotorConfigurationID(id);
560 // tube3.setIgnitionEvent(MotorMount.IgnitionEvent.NEVER);
562 rocket.getDefaultConfiguration().setAllStages();