1 package net.sf.openrocket.util;
3 import java.util.Random;
5 import net.sf.openrocket.material.Material;
6 import net.sf.openrocket.material.Material.Type;
7 import net.sf.openrocket.motor.Motor;
8 import net.sf.openrocket.rocketcomponent.BodyTube;
9 import net.sf.openrocket.rocketcomponent.Bulkhead;
10 import net.sf.openrocket.rocketcomponent.CenteringRing;
11 import net.sf.openrocket.rocketcomponent.ExternalComponent;
12 import net.sf.openrocket.rocketcomponent.ExternalComponent.Finish;
13 import net.sf.openrocket.rocketcomponent.FinSet.CrossSection;
14 import net.sf.openrocket.rocketcomponent.FreeformFinSet;
15 import net.sf.openrocket.rocketcomponent.IllegalFinPointException;
16 import net.sf.openrocket.rocketcomponent.InnerTube;
17 import net.sf.openrocket.rocketcomponent.InternalComponent;
18 import net.sf.openrocket.rocketcomponent.LaunchLug;
19 import net.sf.openrocket.rocketcomponent.MassComponent;
20 import net.sf.openrocket.rocketcomponent.MotorMount.IgnitionEvent;
21 import net.sf.openrocket.rocketcomponent.NoseCone;
22 import net.sf.openrocket.rocketcomponent.ReferenceType;
23 import net.sf.openrocket.rocketcomponent.Rocket;
24 import net.sf.openrocket.rocketcomponent.RocketComponent;
25 import net.sf.openrocket.rocketcomponent.RocketComponent.Position;
26 import net.sf.openrocket.rocketcomponent.Stage;
27 import net.sf.openrocket.rocketcomponent.Transition;
28 import net.sf.openrocket.rocketcomponent.Transition.Shape;
29 import net.sf.openrocket.rocketcomponent.TrapezoidFinSet;
30 import net.sf.openrocket.rocketcomponent.TubeCoupler;
31 import net.sf.openrocket.startup.Application;
33 public class TestRockets {
35 private final String key;
36 private final Random rnd;
39 public TestRockets(String key) {
42 Random rnd = new Random();
43 StringBuilder sb = new StringBuilder();
44 for (int i = 0; i < 6; i++) {
45 int n = rnd.nextInt(62);
47 sb.append((char) ('0' + n));
49 sb.append((char) ('A' + n - 10));
51 sb.append((char) ('a' + n - 36));
58 this.rnd = new Random(key.hashCode());
64 * Create a new test rocket based on the value 'key'. The rocket utilizes most of the
65 * properties and features available. The same key always returns the same rocket,
66 * but different key values produce slightly different rockets. A key value of
67 * <code>null</code> generates a rocket using a random key.
69 * The rocket created by this method is not fly-worthy. It is also NOT guaranteed
70 * that later versions would produce exactly the same rocket!
72 * @return a rocket design.
74 public Rocket makeTestRocket() {
76 Rocket rocket = new Rocket();
78 rocket.setCustomReferenceLength(rnd(0.05));
79 rocket.setDesigner("Designer " + key);
80 rocket.setReferenceType((ReferenceType) randomEnum(ReferenceType.class));
81 rocket.setRevision("Rocket revision " + key);
85 Stage stage = new Stage();
87 rocket.addChild(stage);
90 NoseCone nose = new NoseCone();
92 nose.setAftRadius(rnd(0.03));
93 nose.setAftRadiusAutomatic(rnd.nextBoolean());
94 nose.setAftShoulderCapped(rnd.nextBoolean());
95 nose.setAftShoulderLength(rnd(0.02));
96 nose.setAftShoulderRadius(rnd(0.02));
97 nose.setAftShoulderThickness(rnd(0.002));
98 nose.setClipped(rnd.nextBoolean());
99 nose.setThickness(rnd(0.002));
100 nose.setFilled(rnd.nextBoolean());
101 nose.setForeRadius(rnd(0.1)); // Unset
102 nose.setLength(rnd(0.15));
103 nose.setShapeParameter(rnd(0.5));
104 nose.setType((Shape) randomEnum(Shape.class));
105 stage.addChild(nose);
108 Transition shoulder = new Transition();
110 shoulder.setAftRadius(rnd(0.06));
111 shoulder.setAftRadiusAutomatic(rnd.nextBoolean());
112 shoulder.setAftShoulderCapped(rnd.nextBoolean());
113 shoulder.setAftShoulderLength(rnd(0.02));
114 shoulder.setAftShoulderRadius(rnd(0.05));
115 shoulder.setAftShoulderThickness(rnd(0.002));
116 shoulder.setClipped(rnd.nextBoolean());
117 shoulder.setThickness(rnd(0.002));
118 shoulder.setFilled(rnd.nextBoolean());
119 shoulder.setForeRadius(rnd(0.03));
120 shoulder.setForeRadiusAutomatic(rnd.nextBoolean());
121 shoulder.setForeShoulderCapped(rnd.nextBoolean());
122 shoulder.setForeShoulderLength(rnd(0.02));
123 shoulder.setForeShoulderRadius(rnd(0.02));
124 shoulder.setForeShoulderThickness(rnd(0.002));
125 shoulder.setLength(rnd(0.15));
126 shoulder.setShapeParameter(rnd(0.5));
127 shoulder.setThickness(rnd(0.003));
128 shoulder.setType((Shape) randomEnum(Shape.class));
129 stage.addChild(shoulder);
132 BodyTube body = new BodyTube();
134 body.setThickness(rnd(0.002));
135 body.setFilled(rnd.nextBoolean());
136 body.setIgnitionDelay(rnd.nextDouble() * 3);
137 body.setIgnitionEvent((IgnitionEvent) randomEnum(IgnitionEvent.class));
138 body.setLength(rnd(0.3));
139 body.setMotorMount(rnd.nextBoolean());
140 body.setMotorOverhang(rnd.nextGaussian() * 0.03);
141 body.setOuterRadius(rnd(0.06));
142 body.setOuterRadiusAutomatic(rnd.nextBoolean());
143 stage.addChild(body);
146 Transition boattail = new Transition();
148 boattail.setAftRadius(rnd(0.03));
149 boattail.setAftRadiusAutomatic(rnd.nextBoolean());
150 boattail.setAftShoulderCapped(rnd.nextBoolean());
151 boattail.setAftShoulderLength(rnd(0.02));
152 boattail.setAftShoulderRadius(rnd(0.02));
153 boattail.setAftShoulderThickness(rnd(0.002));
154 boattail.setClipped(rnd.nextBoolean());
155 boattail.setThickness(rnd(0.002));
156 boattail.setFilled(rnd.nextBoolean());
157 boattail.setForeRadius(rnd(0.06));
158 boattail.setForeRadiusAutomatic(rnd.nextBoolean());
159 boattail.setForeShoulderCapped(rnd.nextBoolean());
160 boattail.setForeShoulderLength(rnd(0.02));
161 boattail.setForeShoulderRadius(rnd(0.05));
162 boattail.setForeShoulderThickness(rnd(0.002));
163 boattail.setLength(rnd(0.15));
164 boattail.setShapeParameter(rnd(0.5));
165 boattail.setThickness(rnd(0.003));
166 boattail.setType((Shape) randomEnum(Shape.class));
167 stage.addChild(boattail);
170 MassComponent mass = new MassComponent();
172 mass.setComponentMass(rnd(0.05));
173 mass.setLength(rnd(0.05));
174 mass.setRadialDirection(rnd(100));
175 mass.setRadialPosition(rnd(0.02));
176 mass.setRadius(rnd(0.05));
186 private void setBasics(RocketComponent c) {
187 c.setComment(c.getComponentName() + " comment " + key);
188 c.setName(c.getComponentName() + " name " + key);
190 c.setCGOverridden(rnd.nextBoolean());
191 c.setMassOverridden(rnd.nextBoolean());
192 c.setOverrideCGX(rnd(0.2));
193 c.setOverrideMass(rnd(0.05));
194 c.setOverrideSubcomponents(rnd.nextBoolean());
197 // Only massive components are drawn
198 c.setColor(randomColor());
199 c.setLineStyle((LineStyle) randomEnum(LineStyle.class));
202 if (c instanceof ExternalComponent) {
203 ExternalComponent e = (ExternalComponent) c;
204 e.setFinish((Finish) randomEnum(Finish.class));
206 e.setMaterial(Material.newUserMaterial(Type.BULK, "Testmat " + d, d));
209 if (c instanceof InternalComponent) {
210 InternalComponent i = (InternalComponent) c;
211 i.setRelativePosition((Position) randomEnum(Position.class));
212 i.setPositionValue(rnd(0.3));
218 private double rnd(double scale) {
219 return (rnd.nextDouble() * 0.2 + 0.9) * scale;
222 private Color randomColor() {
223 return new Color(rnd.nextInt(256), rnd.nextInt(256), rnd.nextInt(256));
226 private <T extends Enum<T>> Enum<T> randomEnum(Class<T> c) {
227 Enum<T>[] values = c.getEnumConstants();
228 if (values.length == 0)
231 return values[rnd.nextInt(values.length)];
238 public Rocket makeSmallFlyable() {
239 double noseconeLength = 0.10, noseconeRadius = 0.01;
240 double bodytubeLength = 0.20, bodytubeRadius = 0.01, bodytubeThickness = 0.001;
243 double finRootChord = 0.04, finTipChord = 0.05, finSweep = 0.01, finThickness = 0.003, finHeight = 0.03;
250 TrapezoidFinSet finset;
252 rocket = new Rocket();
254 stage.setName("Stage1");
256 nosecone = new NoseCone(Transition.Shape.ELLIPSOID, noseconeLength, noseconeRadius);
257 bodytube = new BodyTube(bodytubeLength, bodytubeRadius, bodytubeThickness);
259 finset = new TrapezoidFinSet(finCount, finRootChord, finTipChord, finSweep, finHeight);
262 // Stage construction
263 rocket.addChild(stage);
266 // Component construction
267 stage.addChild(nosecone);
268 stage.addChild(bodytube);
270 bodytube.addChild(finset);
272 Material material = Application.getPreferences().getDefaultComponentMaterial(null, Material.Type.BULK);
273 nosecone.setMaterial(material);
274 bodytube.setMaterial(material);
275 finset.setMaterial(material);
277 String id = rocket.newMotorConfigurationID();
278 bodytube.setMotorMount(true);
280 Motor m = Application.getMotorSetDatabase().findMotors(null, null, "B4", Double.NaN, Double.NaN).get(0);
281 bodytube.setMotor(id, m);
282 bodytube.setMotorOverhang(0.005);
283 rocket.getDefaultConfiguration().setMotorConfigurationID(id);
285 rocket.getDefaultConfiguration().setAllStages();
292 public static Rocket makeBigBlue() {
297 FreeformFinSet finset;
300 rocket = new Rocket();
302 stage.setName("Stage1");
304 nosecone = new NoseCone(Transition.Shape.ELLIPSOID, 0.105, 0.033);
305 nosecone.setThickness(0.001);
306 bodytube = new BodyTube(0.69, 0.033, 0.001);
308 finset = new FreeformFinSet();
310 finset.setPoints(new Coordinate[] {
311 new Coordinate(0, 0),
312 new Coordinate(0.115, 0.072),
313 new Coordinate(0.255, 0.072),
314 new Coordinate(0.255, 0.037),
315 new Coordinate(0.150, 0)
317 } catch (IllegalFinPointException e) {
320 finset.setThickness(0.003);
321 finset.setFinCount(4);
323 finset.setCantAngle(0 * Math.PI / 180);
324 System.err.println("Fin cant angle: " + (finset.getCantAngle() * 180 / Math.PI));
326 mcomp = new MassComponent(0.2, 0.03, 0.045 + 0.060);
327 mcomp.setRelativePosition(Position.TOP);
328 mcomp.setPositionValue(0);
330 // Stage construction
331 rocket.addChild(stage);
332 rocket.setPerfectFinish(false);
335 // Component construction
336 stage.addChild(nosecone);
337 stage.addChild(bodytube);
339 bodytube.addChild(finset);
341 bodytube.addChild(mcomp);
343 // Material material = new Material("Test material", 500);
344 // nosecone.setMaterial(material);
345 // bodytube.setMaterial(material);
346 // finset.setMaterial(material);
348 String id = rocket.newMotorConfigurationID();
349 bodytube.setMotorMount(true);
351 // Motor m = Application.getMotorSetDatabase().findMotors(null, null, "F12J", Double.NaN, Double.NaN).get(0);
352 // bodytube.setMotor(id, m);
353 // bodytube.setMotorOverhang(0.005);
354 rocket.getDefaultConfiguration().setMotorConfigurationID(id);
356 rocket.getDefaultConfiguration().setAllStages();
364 public static Rocket makeIsoHaisu() {
368 BodyTube tube1, tube2, tube3;
369 TrapezoidFinSet finset;
370 TrapezoidFinSet auxfinset;
373 final double R = 0.07;
375 rocket = new Rocket();
377 stage.setName("Stage1");
379 nosecone = new NoseCone(Transition.Shape.OGIVE, 0.53, R);
380 nosecone.setThickness(0.005);
381 nosecone.setMassOverridden(true);
382 nosecone.setOverrideMass(0.588);
383 stage.addChild(nosecone);
385 tube1 = new BodyTube(0.505, R, 0.005);
386 tube1.setMassOverridden(true);
387 tube1.setOverrideMass(0.366);
388 stage.addChild(tube1);
390 tube2 = new BodyTube(0.605, R, 0.005);
391 tube2.setMassOverridden(true);
392 tube2.setOverrideMass(0.427);
393 stage.addChild(tube2);
395 tube3 = new BodyTube(1.065, R, 0.005);
396 tube3.setMassOverridden(true);
397 tube3.setOverrideMass(0.730);
398 stage.addChild(tube3);
401 LaunchLug lug = new LaunchLug();
404 TubeCoupler coupler = new TubeCoupler();
405 coupler.setOuterRadiusAutomatic(true);
406 coupler.setThickness(0.005);
407 coupler.setLength(0.28);
408 coupler.setMassOverridden(true);
409 coupler.setOverrideMass(0.360);
410 coupler.setRelativePosition(Position.BOTTOM);
411 coupler.setPositionValue(-0.14);
412 tube1.addChild(coupler);
416 MassComponent mass = new MassComponent(0.05, 0.05, 0.280);
417 mass.setRelativePosition(Position.TOP);
418 mass.setPositionValue(0.2);
419 tube1.addChild(mass);
422 mass = new MassComponent(0.05, 0.05, 0.125);
423 mass.setRelativePosition(Position.TOP);
424 mass.setPositionValue(0.2);
425 tube1.addChild(mass);
428 mass = new MassComponent(0.40, R, 1.500);
429 mass.setRelativePosition(Position.TOP);
430 mass.setPositionValue(0.25);
431 tube1.addChild(mass);
434 auxfinset = new TrapezoidFinSet();
435 auxfinset.setName("CONTROL");
436 auxfinset.setFinCount(2);
437 auxfinset.setRootChord(0.05);
438 auxfinset.setTipChord(0.05);
439 auxfinset.setHeight(0.10);
440 auxfinset.setSweep(0);
441 auxfinset.setThickness(0.008);
442 auxfinset.setCrossSection(CrossSection.AIRFOIL);
443 auxfinset.setRelativePosition(Position.TOP);
444 auxfinset.setPositionValue(0.28);
445 auxfinset.setBaseRotation(Math.PI / 2);
446 tube1.addChild(auxfinset);
451 coupler = new TubeCoupler();
452 coupler.setOuterRadiusAutomatic(true);
453 coupler.setLength(0.28);
454 coupler.setRelativePosition(Position.TOP);
455 coupler.setPositionValue(0.47);
456 coupler.setMassOverridden(true);
457 coupler.setOverrideMass(0.360);
458 tube2.addChild(coupler);
463 mass = new MassComponent(0.1, 0.05, 0.028);
464 mass.setRelativePosition(Position.TOP);
465 mass.setPositionValue(0.14);
466 tube2.addChild(mass);
468 Bulkhead bulk = new Bulkhead();
469 bulk.setOuterRadiusAutomatic(true);
470 bulk.setMassOverridden(true);
471 bulk.setOverrideMass(0.050);
472 bulk.setRelativePosition(Position.TOP);
473 bulk.setPositionValue(0.27);
474 tube2.addChild(bulk);
477 mass = new MassComponent(0.1, 0.05, 0.125);
478 mass.setRelativePosition(Position.TOP);
479 mass.setPositionValue(0.19);
480 tube2.addChild(mass);
484 InnerTube inner = new InnerTube();
485 inner.setOuterRadius(0.08 / 2);
486 inner.setInnerRadius(0.0762 / 2);
487 inner.setLength(0.86);
488 inner.setMassOverridden(true);
489 inner.setOverrideMass(0.388);
490 tube3.addChild(inner);
493 CenteringRing center = new CenteringRing();
494 center.setInnerRadiusAutomatic(true);
495 center.setOuterRadiusAutomatic(true);
496 center.setLength(0.005);
497 center.setMassOverridden(true);
498 center.setOverrideMass(0.038);
499 center.setRelativePosition(Position.BOTTOM);
500 center.setPositionValue(0);
501 tube3.addChild(center);
504 center = new CenteringRing();
505 center.setInnerRadiusAutomatic(true);
506 center.setOuterRadiusAutomatic(true);
507 center.setLength(0.005);
508 center.setMassOverridden(true);
509 center.setOverrideMass(0.038);
510 center.setRelativePosition(Position.TOP);
511 center.setPositionValue(0.28);
512 tube3.addChild(center);
515 center = new CenteringRing();
516 center.setInnerRadiusAutomatic(true);
517 center.setOuterRadiusAutomatic(true);
518 center.setLength(0.005);
519 center.setMassOverridden(true);
520 center.setOverrideMass(0.038);
521 center.setRelativePosition(Position.TOP);
522 center.setPositionValue(0.83);
523 tube3.addChild(center);
529 finset = new TrapezoidFinSet();
530 finset.setRootChord(0.495);
531 finset.setTipChord(0.1);
532 finset.setHeight(0.185);
533 finset.setThickness(0.005);
534 finset.setSweep(0.3);
535 finset.setRelativePosition(Position.BOTTOM);
536 finset.setPositionValue(-0.03);
537 finset.setBaseRotation(Math.PI / 2);
538 tube3.addChild(finset);
541 finset.setCantAngle(0 * Math.PI / 180);
542 System.err.println("Fin cant angle: " + (finset.getCantAngle() * 180 / Math.PI));
545 // Stage construction
546 rocket.addChild(stage);
547 rocket.setPerfectFinish(false);
551 String id = rocket.newMotorConfigurationID();
552 tube3.setMotorMount(true);
554 // Motor m = Application.getMotorSetDatabase().findMotors(null, null, "L540", Double.NaN, Double.NaN).get(0);
555 // tube3.setMotor(id, m);
556 // tube3.setMotorOverhang(0.02);
557 rocket.getDefaultConfiguration().setMotorConfigurationID(id);
559 // tube3.setIgnitionEvent(MotorMount.IgnitionEvent.NEVER);
561 rocket.getDefaultConfiguration().setAllStages();